UVA - 11996(splay入门)

本题目的操作是维护01序列。

并需要动态比较序列当前任意两个位置后缀的LCP。

那么只需要用splay维护序列的同时,再维护一个域(当前所在子树01序列的hash值),查找时就可以用伸展树的分裂和合并操作提取所需子树hash值,然后二分即可。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
typedef unsigned long long llu;
#define rep1(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) for(int i=0;i<(int)n;i++)
const int maxn = 5e5 + 100;
const llu base = 3137;
llu BA[maxn];
typedef struct node* pointer;
struct node{
   pointer ch[2];
   int c,flip,v;
   llu ha[2];
   node(int v=0):v(v){c = 1 ; ha[0]=ha[1]=v; ch[1]=ch[0]=NULL; flip=0;}
   int cl(){return ch[0]==NULL ? 0 : ch[0]->c;}
   int cr(){return ch[1]==NULL ? 0 : ch[1]->c;}
   llu hal(int d){ return ch[0]==NULL ? 0:ch[0]->ha[d];}
   llu har(int d){ return ch[1]==NULL ? 0:ch[1]->ha[d];}
   int cmp(int x){
      if(x == cl() + 1) return -1;
      return(cl()>=x ? 0 : 1);
   }
   void maintain(){
      if(ch[0]!=NULL) ch[0]->pushdown();
      if(ch[1]!=NULL) ch[1]->pushdown();
      ha[0] = (hal(0)*base + v)*BA[cr()] + har(0);
      ha[1] = (har(1)*base + v)*BA[cl()] + hal(1);
      c = 1 + cl() + cr();
   }
   void pushdown(){
       if(flip){
           flip^=1;
           swap(ch[0],ch[1]);
           swap(ha[0],ha[1]);
           if(ch[0]!=NULL) ch[0]->flip^=1;
           if(ch[1]!=NULL) ch[1]->flip^=1;
       }
   }
};
void rotate(pointer& u,int d){
   pointer te = u->ch[d^1];
   u->ch[d^1] = te->ch[d];
   te->ch[d] = u;
   u->maintain(); te->maintain();
   u = te;
}
void splay(pointer& u,int k){
   u->pushdown();
   int d = u->cmp(k);
   if(d!=-1){
      int k2 = (u->cl()>=k ? k : k-u->cl()-1);
      pointer te = u->ch[d];
      te->pushdown();
      int d2 = te->cmp(k2);
      if(d2!=-1){
          splay(te->ch[d2],d2==0 ? k2 : k2-te->cl()-1);
          if(d2 == d) rotate(u , d^1); else rotate(u->ch[d],d2^1);
      }
      rotate(u , d^1);
   }
}
void split(pointer u ,int k , pointer& le ,pointer& ri){
    splay(u,k);
    le = u;
    ri = le->ch[1];
    le->ch[1] = NULL;
    le->maintain();
}
pointer merge_(pointer le , pointer ri){
    splay(le,le->c);
    le->ch[1] = ri;
    le->maintain();
    return le;
}
pointer insert_(pointer u , int p,int v){
    pointer le,ri;
    split(u,p,le,ri);
    le->ch[1]=new node(v);
    le->maintain();
    return merge_(le,ri);
}
pointer erase_(pointer u, int p){
    pointer le,ri;
    split(u,p,le,ri);
    pointer te = le;
    le=le->ch[0];
    delete te;
    return merge_(le,ri);
}
pointer flip_(pointer u,int p1,int p2){
   pointer le,mid,ri,te;
   split(u,p1,le,te);
   split(te,p2-p1+1,mid,ri);
   mid->flip^=1;
   return merge_(merge_(le,mid),ri);
}
llu cal(pointer& u,int len,int p){
   pointer le,mid,ri,te;
   split(u,p,le,te);
   split(te,len,mid,ri);
   llu tte = mid->ha[0];
   u = merge_(merge_(le,mid),ri);
   return tte;
}
int judge(pointer& u, int len,int p1,int p2){
    return (cal(u,len,p1)==cal(u,len,p2));
}
int find_(pointer& u ,int p1,int p2){
   int n = u->c-1;
   int l=1,r=n-max(p1,p2)+1;
   if(judge(u,r,p1,p2)) return r;
   while(l<r){
      int m=(l+r)>>1;
      if(judge(u,m,p1,p2)) l=m+1;
      else r=m;
   }
   return l-1;
}
int n,Q;
char str[maxn];
pointer root;
void show(pointer u){
   u->pushdown();
   if(u == NULL) return ;
   show(u->ch[0]);
   printf("%d",u->v);
   show(u->ch[1]);
}
void del(pointer& u){
    if(u==NULL) return ;
    del(u->ch[0]); del(u->ch[1]);
    delete u;
    u = NULL;
}
int main()
{
   BA[0] = 1;
   rep1(i,1,maxn-1) BA[i]=BA[i-1]*base;
   while(scanf("%d %d",&n,&Q)==2){
      scanf("%s",str);
      del(root);
      root=NULL;
      for(int i=n-1;i>=0;i--) {
         pointer te=new node(str[i]-'0');
         te->ch[1]=root; root = te;
         root->maintain();
      }
      pointer te=new node(0);
      te->ch[1]=root; root = te;
      root->maintain();
      while(Q--){
         int cmd,p1,p2;
         scanf("%d %d",&cmd,&p1);
         if(cmd!=2) scanf("%d",&p2);
         if(cmd==1){
             p1++; root = insert_(root,p1,p2);
         }
         else if(cmd==2){
             p1++; root = erase_(root,p1);
         }
         else if(cmd==3){
             root=flip_(root,p1,p2);
         }
         else {
             int ans = find_(root,p1,p2);
             printf("%d\n",ans);
         }
      }
   }
   return 0;
}
/*
3 10
000
2 1
2 1
2 1
1 0 1
*/


你可能感兴趣的:(UVA - 11996(splay入门))