poj3580 伸展树(区间翻转 区间搬移 删除结点 加入结点 成段更新)
好题。我做了很久,学了大牛们的区间搬移。主要的代码都有注释。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define INF 999999999 #define key_value ch[ch[root][1]][0] using namespace std; const int MAXN = 200010; int pre[MAXN],lazy[MAXN],siz[MAXN],ch[MAXN][2],s[MAXN],key[MAXN],tot1,tot2,root,ans[MAXN]; int n,a[MAXN],rev[MAXN];//rev表示旋转 lazy标记增加的量 /****************************/ void Treavel(int x) { if(x) { Treavel(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size=%2d,key=%2d lazy=%2d rev=%2d ans=%2d\n",x,ch[x][0],ch[x][1],pre[x],siz[x],key[x],lazy[x],rev[x],ans[x]); Treavel(ch[x][1]); } } void debug() { printf("root:%d\n",root); Treavel(root); } /****************************/ void Newnode(int &rt,int pa,int k) { if(tot2) rt = s[--tot2]; else rt = ++tot1; pre[rt] = pa; key[rt] = k; lazy[rt] = 0; siz[rt] = 1; rev[rt] = 0; ans[rt] = k; ch[rt][0] = ch[rt][1] = 0; } void pushup(int rt) { siz[rt] = siz[ch[rt][0]] + siz[ch[rt][1]] + 1; ans[rt] = key[rt]; if(ch[rt][0]) //因为是min ans[rt] = min(ans[rt],ans[ch[rt][0]]); if(ch[rt][1]) ans[rt] = min(ans[rt],ans[ch[rt][1]]); } void pushdown(int rt) { if(rev[rt]){ rev[ch[rt][0]] ^= 1; rev[ch[rt][1]] ^= 1; swap(ch[rt][0],ch[rt][1]); rev[rt] = 0; } if(lazy[rt]){ lazy[ch[rt][0]] += lazy[rt]; lazy[ch[rt][1]] += lazy[rt]; key[ch[rt][0]] += lazy[rt]; key[ch[rt][1]] += lazy[rt]; ans[ch[rt][0]] += lazy[rt]; ans[ch[rt][1]] += lazy[rt]; lazy[rt] = 0; } } void build(int &rt,int l,int r,int pa) { if(l > r) return ; int m = (l+r)/2; Newnode(rt,pa,a[m]); build(ch[rt][0],l,m-1,rt); build(ch[rt][1],m+1,r,rt); pushup(rt); } void Init() { tot1 = tot2 = root = 0; siz[root] = pre[root] = lazy[root] = key[root] = rev[root] = 0; ans[root] = INF; ch[root][0] = ch[root][1] = 0; Newnode(root,0,-1); Newnode(ch[root][1],root,-1); build(key_value,1,n,ch[root][1]); pushup(ch[root][1]); pushup(root); } //先pushdown将lazy压下去 void Rotate(int rt,int kind) { pushdown(pre[rt]); pushdown(rt); int y = pre[rt]; ch[y][!kind] = ch[rt][kind]; pre[ch[rt][kind]] = y; if(pre[y]){ ch[pre[y]][ch[pre[y]][1]==y] = rt; } pre[rt] = pre[y]; ch[rt][kind] = y; pre[y] = rt; pushup(y); pushup(rt); } //先pushdown将lazy压下去 void splay(int rt,int goal) { pushdown(rt); while(pre[rt] != goal) { if(pre[pre[rt]] == goal){ pushdown(pre[rt]); pushdown(rt); Rotate(rt,ch[pre[rt]][0]==rt); } else { pushdown(pre[pre[rt]]); pushdown(pre[rt]); pushdown(rt); int y = pre[rt]; int kind = ch[pre[y]][0]==y; if(ch[y][kind] == rt){ Rotate(rt,!kind); Rotate(rt,kind); } else { Rotate(y,kind); Rotate(rt,kind); } } } pushup(rt); if(goal == 0) root = rt; } int Get_kth(int rt,int k) { pushdown(rt); int t = siz[ch[rt][0]] + 1; if(t == k) return rt; else if(t > k){ return Get_kth(ch[rt][0],k); } else { return Get_kth(ch[rt][1],k-t); } pushup(rt); } void add(int x,int y,int z) { splay(Get_kth(root,x),0); splay(Get_kth(root,y+2),root); lazy[key_value] += z; key[key_value] += z; ans[key_value] += z; pushup(ch[root][1]); pushup(root);// } int Get_min(int rt) { pushdown(rt); while(ch[rt][0]){ rt = ch[rt][0]; pushdown(rt); } return rt; } int Get_max(int rt) { pushdown(rt); while(ch[rt][1]){ rt = ch[rt][1]; pushdown(rt); } return rt; } int query(int x,int y) { splay(Get_kth(root,x),0); splay(Get_kth(root,y+2),root); return ans[key_value]; } void Del(int x) { splay(Get_kth(root,x),0); splay(Get_kth(root,x+2),root); pre[key_value] = 0; key_value = 0; pushup(ch[root][1]); pushup(root); } void Insert(int x,int y) { splay(Get_kth(root,x+1),0); splay(Get_kth(root,x+2),root); Newnode(key_value,ch[root][1],y); pushup(ch[root][1]); pushup(root); } void Reverse(int x,int y) { splay(Get_kth(root,x),0); splay(Get_kth(root,y+2),root); rev[key_value] ^= 1; pushup(ch[root][1]); pushup(root); } void Revolve(int l,int r,int t) { //区间平移其实就是把区间[l,c-1],[c,r]中的[c,r]放到[l,c-1]前 int len = r - l + 1;//取mod t = (t%len + len)%len; if(!t)return ; int c = r - t + 1; splay(Get_kth(root,c),0); splay(Get_kth(root,r+2),root); int tmp = key_value;//这里的是[c,r]的区间 key_value = 0; pushup(ch[root][1]); pushup(root);//注意这两步 这里把key_value取0 这样主要为了取走[c,r],所以要更新 splay(Get_kth(root,l),0); splay(Get_kth(root,l+1),root); key_value = tmp; pre[key_value] = ch[root][1]; pushup(ch[root][1]); pushup(root); } int main() { int i,j; while(~scanf("%d",&n)) { for(i=1; i<=n; i++){ scanf("%d",&a[i]); } Init(); int q; scanf("%d",&q); char work[10]; //debug(); //cout<<"test: "<<endl; while(q--) { scanf("%s",work); if(work[0] == 'A'){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); //debug(); } else if(work[0] == 'M'){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",query(x,y)); } else if(work[0] == 'D'){ int x; scanf("%d",&x); Del(x); //debug(); } else if(work[0] == 'I'){ int x,y; scanf("%d%d",&x,&y); Insert(x,y); //debug(); } else if(strcmp(work,"REVERSE") == 0){ int x,y; scanf("%d%d",&x,&y); Reverse(x,y); //debug(); } else if(strcmp(work,"REVOLVE") == 0){ int x,y,ft; scanf("%d%d%d",&x,&y,&ft); Revolve(x,y,ft); //debug(); } } } }