洛谷 P3285 [SCOI2014]方伯伯的OJ

看到这题,第一眼:平衡树水题,随便做一做好了

然后....我在花了n个小时去调试(维护平衡树父节点)之后,...

调了三个小时后,第一次失败的代码(只能查找排名为k的用户编号,不能根据编号查排名)

#include<cstdio>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;

int r[300100],lx[300100],rx[300100],sz[300100],ch[300100][2];
map<int,int> ma,ma2;
queue<int> q;
int getnode()
{
    int t=q.front();q.pop();return t;
}
void delnode(int x)
{
    q.push(x);
}
int rand1()
{
    static int x=131;
    return x=(48271LL*x+1)%2147483647;
}
void upd(int x)
{
    //sz[x]=sz[ch[x][0]]+sz[ch[x][1]];
    sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rx[x]-lx[x]+1;
}
int root;
int merge(int a,int b)
{
    if(!a||!b)    return a+b;
    if(r[a]<r[b])
    {
        ch[a][1]=merge(ch[a][1],b);upd(a);
        return a;
    }
    else
    {
        ch[b][0]=merge(a,ch[b][0]);upd(b);
        return b;
    }
}
typedef pair<int,int> P;
P split(int a,int n)//a的前n个放入first,剩余放入second
{
    if(!a)    return P(0,0);
    int s=sz[ch[a][0]];P t;
    if(s>=n)
    {
        t=split(ch[a][0],n);ch[a][0]=t.second;upd(a);
        return P(t.first,a);
    }
    else
    {
        t=split(ch[a][1],n-s-1);ch[a][1]=t.first;upd(a);
        return P(a,t.second);
    }
}
P find(int x)
{
    int num=root;P t;t.second=0;
    while(1)
    {
        if(lx[num]>x)    num=ch[num][0];
        else    if(rx[num]<x)    t.second+=sz[ch[num][0]]+rx[num]-lx[num]+1,num=ch[num][1];
        else    break;
    }
    t.first=num;
    return t;
}
P find_kth(int k)
{
    int num=root,ls;P t;t.second=0;
    while(1)
    {
        ls=sz[ch[num][0]];
        if(ls>=k)    num=ch[num][0];
        else    if(ls+rx[num]-lx[num]+1>=k)    break;
        else    t.second+=ls+rx[num]-lx[num]+1,num=ch[num][1];
    }
    t.first=num;
    return t;
}
int newnode(int L,int R)
{
    int t=getnode();r[t]=rand1();lx[t]=L;rx[t]=R;sz[t]=R-L+1;
    return t;
}
int n,m,lans;
int main()
{
    P t1,t2,t3;
    int x,y,t,ta,tb,tc,i,idx;
    for(i=1;i<300000;i++)    q.push(i);
    scanf("%d%d",&n,&m);
    root=getnode();lx[root]=1;rx[root]=n;sz[root]=n;r[root]=rand1();
    for(i=1;i<=m;i++)
    {
        scanf("%d",&idx);
        if(idx==1)
        {
            scanf("%d%d",&x,&y);x-=lans;y-=lans;
            if(ma.count(x))//ma记录用户编号对应的虚拟编号
            {
                t=ma[x];ma.erase(x);ma[y]=x;
                ma2[t]=y;//ma2反过来
            }
            else
            {
                t=x;ma[y]=x;ma2[t]=y;
            }
            //t1=find(y);lans=t1.second+y-lx[t1.first]+1;
            t1=find(t);lans=t1.second+t-lx[t1.first]+1;
            printf("%d
",lans);
        }
        else if(idx==2)
        {
            scanf("%d",&x);x-=lans;x=ma.count(x)?ma[x]:x;
            t1=find(x);t=t1.second+x-lx[t1.first]+1;
            t2=split(root,t1.second);t3=split(t2.second,rx[t1.first]-lx[t1.first]+1);
            if(lx[t3.first]!=x)
            {
                ta=newnode(lx[t3.first],x-1);
            }
            else
                ta=0;
            tb=newnode(x,x);
            if(rx[t3.first]!=x)
            {
                tc=newnode(x+1,rx[t3.first]);
            }
            else
                tc=0;
            delnode(t3.first);
            root=merge(merge(tb,t2.first),merge(ta,merge(tc,t3.second)));
            printf("%d
",t);lans=t;
        }
        else if(idx==3)
        {
            scanf("%d",&x);x-=lans;x=ma.count(x)?ma[x]:x;
            t1=find(x);t=t1.second+x-lx[t1.first]+1;
            t2=split(root,t1.second);t3=split(t2.second,rx[t1.first]-lx[t1.first]+1);
            if(lx[t3.first]!=x)
            {
                ta=newnode(lx[t3.first],x-1);
            }
            else
                ta=0;
            tb=newnode(x,x);
            if(rx[t3.first]!=x)
            {
                tc=newnode(x+1,rx[t3.first]);
            }
            else
                tc=0;
            root=merge(merge(t2.first,ta),merge(tc,merge(t3.second,tb)));
            printf("%d
",t);lans=t;
        }
        else if(idx==4)
        {
            scanf("%d",&x);x-=lans;x=ma.count(x)?ma[x]:x;
            t1=find_kth(x);
            t=t1.first+t1.second-lx[t1.first]+1;
            lans=ma2.count(t)?ma2[t]:t;
            printf("%d
",lans);
        }
    }
    return 0;
}
View Code

 又是四个小时后,第二次失败的代码(由于只记录了编号对应的root或ch[][]中某位置的指针,拆分某节点时无法一并改变这些关联的指针)

#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#define N 100005
using namespace std;
typedef pair<int,int> P;
typedef pair<P,int*> P2;

int lx[N],rx[N],sz[N],fa[N],ch[N][2],r[N];
map<P,int*> ma;
queue<int> q;
int root;
int rand1()
{
    static int x=471;
    return x=(48271LL*x+1)%2147483647;
}
int getnode()
{
    int t=q.front();q.pop();r[t]=rand1();
    lx[t]=rx[t]=sz[t]=fa[t]=ch[t][0]=ch[t][1]=0;
    return t;
}
void delnode(int x)    {q.push(x);}
void upd(int x)    {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rx[x]-lx[x]+1;}

P split(int a,int n)
{
    if(!a)    return P(0,0);
    int ls=sz[ch[a][0]];P t;
    if(n<=ls)
    {
        t=split(ch[a][0],n);ch[a][0]=t.second;
        if(ch[a][0])    fa[ch[a][0]]=a;
        upd(a);t.second=a;
    }
    else
    {
        t=split(ch[a][1],n-ls-1);ch[a][1]=t.first;
        if(ch[a][1])    fa[ch[a][1]]=a;
        upd(a);t.first=a;
    }
    return t;
}

int merge(int a,int b)
{
    if(!a||!b)    return a+b;
    if(r[a]<r[b])
    {
        ch[a][1]=merge(ch[a][1],b);upd(a);
        if(ch[a][1])    fa[ch[a][1]]=a;
        return a;
    }
    else
    {
        ch[b][0]=merge(a,ch[b][0]);upd(b);
        if(ch[b][0])    fa[ch[b][0]]=b;
        return b;
    }
}
int n,m;
int *get_pointer(int x)
{
    if(x==root)    return &root;
    else if(x==ch[fa[x]][0])    return &ch[fa[x]][0];
    else    return &ch[fa[x]][1];
}

void split_node_of_user(int x)
{
    P2 t;int l,r,t1,t2,t3,t4,t5,oo;
    t=*ma.lower_bound(P(x,0));ma.erase(t.first);
    l=t.first.second;r=t.first.first;int &o=*t.second;
    t1=0,t2=0,t3=0,t4=ch[o][0],t5=ch[o][1];
    if(x>l)    {t1=getnode();lx[t1]=l;rx[t1]=x-1;sz[t1]=x-l;}
    t2=getnode();lx[t2]=rx[t2]=x;sz[t2]=1;
    if(x<r)    {t3=getnode();lx[t3]=x+1;rx[t3]=r;sz[t3]=r-x;}
    oo=o;o=merge(merge(t4,t1),merge(merge(t2,t3),t5));fa[o]=fa[oo];
    delnode(oo);
    if(x>l)    ma[P(x-1,l)]=get_pointer(t1);
    ma[P(x,x)]=get_pointer(t2);
    if(x<r)    ma[P(r,x+1)]=get_pointer(t3);
}
int get_rank(int o)
{
    int ans=sz[ch[o][0]];
    while(o!=root)
    {
        if(o==ch[fa[o]][1])    ans+=rx[fa[o]]-lx[fa[o]]+1+sz[ch[fa[o]][0]];
        o=fa[o];
    }
    return ans;
}
int find_kth(int k)
{
    int o=root,ls,ns;
    while(1)
    {
        ls=sz[ch[o][0]];ns=rx[o]-lx[o]+1;
        if(ls>=k)    o=ch[o][0];
        else    if(ls+ns>=k)    break;
        else    k-=(ls+ns),o=ch[o][1];
    }
    return lx[o]+k-1;
}
int get_rank_of_user(int x)
{
    P2 t=*ma.lower_bound(P(x,0));
    return get_rank(*t.second)+x-lx[*t.second];
}

int main()
{
    int i,idx,x,y,t,lans=0;int *tx;P t1,t2;
    for(i=1;i<N;++i)    q.push(i);
    scanf("%d%d",&n,&m);
    root=getnode();lx[root]=1;rx[root]=n;sz[root]=n;ma.insert(P2(P(n,1),&root));
    for(i=1;i<=m;i++)
    {
        scanf("%d",&idx);
        if(idx==1)
        {
            scanf("%d%d",&x,&y);x-=lans;y-=lans;lans=get_rank_of_user(x)+1;
            split_node_of_user(x);tx=ma[P(x,x)];lx[*tx]=rx[*tx]=y;
            ma[P(y,y)]=tx;ma.erase(P(x,x));
            printf("%d
",lans);
        }
        else if(idx==2)
        {
            scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1;
            split_node_of_user(x);t=get_rank(*ma[P(x,x)]);
            t1=split(root,t);t2=split(t1.second,1);
            root=merge(merge(t2.first,t1.first),t2.second);
            printf("%d
",lans);
        }
        else if(idx==3)
        {
            scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1;
            split_node_of_user(x);t=get_rank(*ma[P(x,x)]);
            t1=split(root,t);t2=split(t1.second,1);
            root=merge(merge(t1.first,t2.second),t2.first);
            printf("%d
",lans);
        }
        else if(idx==4)
        {
            scanf("%d",&x);x-=lans;
            printf("%d
",find_kth(x));
        }
    }
    return 0;
}
View Code

 该改的改完之后(包括父节点维护),玄学失败N次的代码

#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#define N 300005
using namespace std;
typedef pair<int,int> P;
typedef pair<P,int> P2;

int lx[N],rx[N],sz[N],fa[N],ch[N][2],r[N];
map<P,int> ma;
queue<int> q;
int root;
int rand1()
{
    static int x=471;
    return x=(48271LL*x+1)%2147483647;
}
int getnode()
{
    int t=q.front();q.pop();r[t]=rand1();
    lx[t]=rx[t]=sz[t]=fa[t]=ch[t][0]=ch[t][1]=0;
    return t;
}
void delnode(int x)    {q.push(x);}
void upd(int x)    {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rx[x]-lx[x]+1;}

P split(int a,int n)
{
    if(!a)    return P(0,0);
    int ls=sz[ch[a][0]];P t;
    if(n<=ls)
    {
        t=split(ch[a][0],n);ch[a][0]=t.second;
        if(ch[a][0])    fa[ch[a][0]]=a;
        upd(a);t.second=a;
    }
    else
    {
        t=split(ch[a][1],n-ls-(rx[a]-lx[a]+1));ch[a][1]=t.first;
        if(ch[a][1])    fa[ch[a][1]]=a;
        upd(a);t.first=a;
    }
    return t;
}

int merge(int a,int b)
{
    if(!a||!b)    return a+b;
    if(r[a]<r[b])
    {
        ch[a][1]=merge(ch[a][1],b);upd(a);
        if(ch[a][1])    fa[ch[a][1]]=a;
        return a;
    }
    else
    {
        ch[b][0]=merge(a,ch[b][0]);upd(b);
        if(ch[b][0])    fa[ch[b][0]]=b;
        return b;
    }
}
int n,m;
int& get_ref(int x)
{
    if(x==root)    return root;
    if(x==ch[fa[x]][0])    return ch[fa[x]][0];
    return ch[fa[x]][1];
}

void split_node_of_user(int x)
{
    P2 t;int l,r,t1,t2,t3,t4,t5,oo;
    t=*ma.lower_bound(P(x,0));ma.erase(t.first);
    l=t.first.second;r=t.first.first;int &o=get_ref(t.second);
    t1=0,t2=0,t3=0,t4=ch[o][0],t5=ch[o][1];
    if(x>l)    {t1=getnode();lx[t1]=l;rx[t1]=x-1;sz[t1]=x-l;}
    t2=getnode();lx[t2]=rx[t2]=x;sz[t2]=1;
    if(x<r)    {t3=getnode();lx[t3]=x+1;rx[t3]=r;sz[t3]=r-x;}
    oo=o;o=merge(merge(t4,t1),merge(merge(t2,t3),t5));fa[o]=fa[oo];
    delnode(oo);
    if(x>l)    ma[P(x-1,l)]=t1;
    ma[P(x,x)]=t2;
    if(x<r)    ma[P(r,x+1)]=t3;
}
int get_rank(int o)
{
    int ans=sz[ch[o][0]];
    while(o!=root)
    {
        if(o==ch[fa[o]][1])    ans+=rx[fa[o]]-lx[fa[o]]+1+sz[ch[fa[o]][0]];
        o=fa[o];
    }
    return ans;
}
int find_kth(int k)
{
    int o=root,ls,ns;
    while(1)
    {
        ls=sz[ch[o][0]];ns=rx[o]-lx[o]+1;
        if(ls>=k)    o=ch[o][0];
        else    if(ls+ns>=k)    {k-=ls;break;}
        else    k-=(ls+ns),o=ch[o][1];
    }
    return lx[o]+k-1;
}
int get_rank_of_user(int x)
{
    P2 t=*ma.lower_bound(P(x,0));
    return get_rank(t.second)+x-lx[t.second];
}
int main()
{
    int i,idx,x,y,t,lans=0;P t1,t2;
    for(i=1;i<N;++i)    q.push(i);
    scanf("%d%d",&n,&m);
    root=getnode();lx[root]=1;rx[root]=n;sz[root]=n;ma.insert(P2(P(n,1),root));
    for(i=1;i<=m;i++)
    {
        scanf("%d",&idx);
        if(idx==1)
        {
            scanf("%d%d",&x,&y);x-=lans;y-=lans;lans=get_rank_of_user(x)+1;
            split_node_of_user(x);t=ma[P(x,x)];lx[t]=rx[t]=y;
            ma[P(y,y)]=t;ma.erase(P(x,x));
            printf("%d
",lans);
        }
        else if(idx==2)
        {
            scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1;
            split_node_of_user(x);t=get_rank(ma[P(x,x)]);
            t1=split(root,t);t2=split(t1.second,1);
            root=merge(merge(t2.first,t1.first),t2.second);
            printf("%d
",lans);
        }
        else if(idx==3)
        {
            scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1;
            split_node_of_user(x);t=get_rank(ma[P(x,x)]);
            t1=split(root,t);t2=split(t1.second,1);
            root=merge(merge(t1.first,t2.second),t2.first);
            printf("%d
",lans);
        }
        else if(idx==4)
        {
            scanf("%d",&x);x-=lans;
            printf("%d
",find_kth(x));
        }
    }
    return 0;
}
View Code

AC代码。AC代码与上面一份代码唯一的区别是在第147行多了一句更新lastans...而且常数巨大233333

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<map>
  4 #include<queue>
  5 #define N 300005
  6 using namespace std;
  7 typedef pair<int,int> P;
  8 typedef pair<P,int> P2;
  9 
 10 int lx[N],rx[N],sz[N],fa[N],ch[N][2],r[N];
 11 map<P,int> ma;
 12 queue<int> q;
 13 int root;
 14 int rand1()
 15 {
 16     static int x=471;
 17     return x=(48271LL*x+1)%2147483647;
 18 }
 19 int getnode()
 20 {
 21     int t=q.front();q.pop();r[t]=rand1();
 22     lx[t]=rx[t]=sz[t]=fa[t]=ch[t][0]=ch[t][1]=0;
 23     return t;
 24 }
 25 void delnode(int x)    {q.push(x);}
 26 void upd(int x)    {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rx[x]-lx[x]+1;}
 27 
 28 P split(int a,int n)
 29 {
 30     if(!a)    return P(0,0);
 31     int ls=sz[ch[a][0]];P t;
 32     if(n<=ls)
 33     {
 34         t=split(ch[a][0],n);ch[a][0]=t.second;
 35         if(ch[a][0])    fa[ch[a][0]]=a;
 36         upd(a);t.second=a;
 37     }
 38     else
 39     {
 40         t=split(ch[a][1],n-ls-(rx[a]-lx[a]+1));ch[a][1]=t.first;
 41         if(ch[a][1])    fa[ch[a][1]]=a;
 42         upd(a);t.first=a;
 43     }
 44     return t;
 45 }
 46 
 47 int merge(int a,int b)
 48 {
 49     if(!a||!b)    return a+b;
 50     if(r[a]<r[b])
 51     {
 52         ch[a][1]=merge(ch[a][1],b);upd(a);
 53         if(ch[a][1])    fa[ch[a][1]]=a;
 54         return a;
 55     }
 56     else
 57     {
 58         ch[b][0]=merge(a,ch[b][0]);upd(b);
 59         if(ch[b][0])    fa[ch[b][0]]=b;
 60         return b;
 61     }
 62 }
 63 int n,m;
 64 int& get_ref(int x)
 65 {
 66     if(x==root)    return root;
 67     if(x==ch[fa[x]][0])    return ch[fa[x]][0];
 68     return ch[fa[x]][1];
 69 }
 70 
 71 void split_node_of_user(int x)
 72 {
 73     P2 t;int l,r,t1,t2,t3,t4,t5,oo;
 74     t=*ma.lower_bound(P(x,0));ma.erase(t.first);
 75     l=t.first.second;r=t.first.first;int &o=get_ref(t.second);
 76     t1=0,t2=0,t3=0,t4=ch[o][0],t5=ch[o][1];
 77     if(x>l)    {t1=getnode();lx[t1]=l;rx[t1]=x-1;sz[t1]=x-l;}
 78     t2=getnode();lx[t2]=rx[t2]=x;sz[t2]=1;
 79     if(x<r)    {t3=getnode();lx[t3]=x+1;rx[t3]=r;sz[t3]=r-x;}
 80     oo=o;o=merge(merge(t4,t1),merge(merge(t2,t3),t5));fa[o]=fa[oo];
 81     delnode(oo);
 82     if(x>l)    ma[P(x-1,l)]=t1;
 83     ma[P(x,x)]=t2;
 84     if(x<r)    ma[P(r,x+1)]=t3;
 85 }
 86 int get_rank(int o)
 87 {
 88     int ans=sz[ch[o][0]];
 89     while(o!=root)
 90     {
 91         if(o==ch[fa[o]][1])    ans+=rx[fa[o]]-lx[fa[o]]+1+sz[ch[fa[o]][0]];
 92         o=fa[o];
 93     }
 94     return ans;
 95 }
 96 int find_kth(int k)
 97 {
 98     int o=root,ls,ns;
 99     while(1)
100     {
101         ls=sz[ch[o][0]];ns=rx[o]-lx[o]+1;
102         if(ls>=k)    o=ch[o][0];
103         else    if(ls+ns>=k)    {k-=ls;break;}
104         else    k-=(ls+ns),o=ch[o][1];
105     }
106     return lx[o]+k-1;
107 }
108 int get_rank_of_user(int x)
109 {
110     P2 t=*ma.lower_bound(P(x,0));
111     return get_rank(t.second)+x-lx[t.second];
112 }
113 int main()
114 {
115     int i,idx,x,y,t,lans=0;P t1,t2;
116     for(i=1;i<N;++i)    q.push(i);
117     scanf("%d%d",&n,&m);
118     root=getnode();lx[root]=1;rx[root]=n;sz[root]=n;ma.insert(P2(P(n,1),root));
119     for(i=1;i<=m;i++)
120     {
121         scanf("%d",&idx);
122         if(idx==1)
123         {
124             scanf("%d%d",&x,&y);x-=lans;y-=lans;lans=get_rank_of_user(x)+1;
125             split_node_of_user(x);t=ma[P(x,x)];lx[t]=rx[t]=y;
126             ma[P(y,y)]=t;ma.erase(P(x,x));
127             printf("%d
",lans);
128         }
129         else if(idx==2)
130         {
131             scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1;
132             split_node_of_user(x);t=get_rank(ma[P(x,x)]);
133             t1=split(root,t);t2=split(t1.second,1);
134             root=merge(merge(t2.first,t1.first),t2.second);
135             printf("%d
",lans);
136         }
137         else if(idx==3)
138         {
139             scanf("%d",&x);x-=lans;lans=get_rank_of_user(x)+1;
140             split_node_of_user(x);t=get_rank(ma[P(x,x)]);
141             t1=split(root,t);t2=split(t1.second,1);
142             root=merge(merge(t1.first,t2.second),t2.first);
143             printf("%d
",lans);
144         }
145         else if(idx==4)
146         {
147             scanf("%d",&x);x-=lans;lans=find_kth(x);
148             printf("%d
",lans);
149         }
150     }
151     return 0;
152 }

从洛谷掏的数据233333

n
1 1000
2 100000
3 100000
4 100000
5 100000000
6 100000000
7 100000000
8 100000000
9 100000000
10 100000000

:1
1 3
2 2
3 2
4 2
5 4
6 3
7 2
8 2
9 3
10 3

:2
01 00000740
02 00080429
03 00079678
04 00058089
05 44174437
06 98466201
07 25431148
08 40131901
09 43505820
10 03752119


:3
01 3
02 2
03 3
04 3
05 2
06 3
07 4
08 3
09 2
10 3

:4
01 000001238
02 000120026
03 000171419
04 000068300
05 094123098
06 107162571
07 061586793
08 069985796
09 083066732
10 005367888

:5
1 3
2 4
3 1
4 4
5 3
6 3
7 2
8 2
9 1
10 2

:6
01 000000907
02 000053848
03 000186311
04 000015145
05 069092662
06 100076086
07 112422962
08 112340967
09 107295244
10 055061511

:7
01 3
02 3
03 000192415
04 2
05 3
06 4
07 4
08 2
09 139958623
10 3

:8
01 000000762
02 000089049
03 4
04 000090777
05 038934093
06 146581036
07 103255266
08 096193795
09 2
10 151256841

:9
01 1
02 4
03 000191572
04 4
05 4
06 3
07 4
08 2
09 073904286
10 2

:10
01 000000984
02 000124275
03 3
04 000134293
05 062449488
06 126079909
07 075280761
08 031377328
09 3
10 099020316

:11
01 000001358
02 2
03 000125643
04 3
05 2
06 4
07 3
08 3
09 077311124
10 3

:12
01 1
02 062617
03 4
04 051355
05 060130743
06 120950877
07 103836077
08 089326104
09 3
10 093010296
 
:13
01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
View Code

具体思路跟NOIP2017D2T3很像....也可以当做平衡树动态开点的某种通用方法...不过细节跟线段树动态开点比的话就23333...

至于具体动态查询编号对应排名的话,用map记录编号对应的节点编号(或一段连续编号对应的同一个节点编号,[l,r]这一段连续编号用P(r,l)表示),然后非旋treap维护序列,记录一下每个节点的父节点,这样就可以根据节点编号查询排名了

(记一下64到85行)

原文地址:https://www.cnblogs.com/hehe54321/p/8531139.html