poj3580 伸展树(区间翻转 区间搬移 删除结点 加入结点 成段更新)
生活随笔
收集整理的這篇文章主要介紹了
poj3580 伸展树(区间翻转 区间搬移 删除结点 加入结点 成段更新)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
好題。我做了很久,學了大牛們的區(qū)間搬移。主要的代碼都有注釋。
#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];elsert = ++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]) //因為是minans[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) {//區(qū)間平移其實就是把區(qū)間[l,c-1],[c,r]中的[c,r]放到[l,c-1]前int len = r - l + 1;//取modt = (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]的區(qū)間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(); }}} }?
轉載于:https://www.cnblogs.com/sweat123/p/5140362.html
總結
以上是生活随笔為你收集整理的poj3580 伸展树(区间翻转 区间搬移 删除结点 加入结点 成段更新)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: App开发(Android与php接口)
- 下一篇: Cocos2d-x 脚本语言Lua中的面