POJ 3580 SuperMemo(伸展树的几个基本操作)
生活随笔
收集整理的這篇文章主要介紹了
POJ 3580 SuperMemo(伸展树的几个基本操作)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:
給定一個數組,對數組進行6種操作。
區間加,區間翻轉,插入一個值,刪除一個值,區間求最小值。
區間循環移位。
題解:
前5種屬于伸展樹的基本操作,區間循環移位需要轉化成基本操作:
區間[l,r]循環右移T位(T=T%(r-l+1) )。相當于區間[l,r-T]和區間[r-T+1,r]?
調換了位置。通過區間刪除和插入可以完成。
??注意:刪除操作需要有內存回收。
?
?
#include<cstdio> #include<cstring> #include<algorithm> #define ddd puts("111"); using namespace std;#define keyv ch[ch[root][1]][0] const int INF = 0x3f3f3f3f; const int maxn = 2e5 + 99;int pre[maxn],sz[maxn],ch[maxn][2],addv[maxn],minv[maxn],key[maxn],rev[maxn],root,tot1; int s[maxn],tot2;///內存池,當有刪除操作的時候進行回收 int a[maxn]; int n,q;void update_add(int r,int add) {if(r==0)return;key[r] += add;minv[r] += add;addv[r] += add; }void update_rev(int r) {if(r == 0)return;swap(ch[r][0],ch[r][1]);rev[r]^=1;///下面的反轉次數+1。 }void pushdown(int r) {if(rev[r]){update_rev(ch[r][0]);update_rev(ch[r][1]);rev[r] = 0;}if(addv[r]){update_add(ch[r][0],addv[r]);update_add(ch[r][1],addv[r]);addv[r] = 0;} }void pushup(int r) {sz[r] = 1 + sz[ch[r][0]]+sz[ch[r][1] ];minv[r] = key[r];if(ch[r][0])minv[r] = min(minv[r],minv[ch[r][0]]);if(ch[r][1])minv[r] = min(minv[r],minv[ch[r][1]]);} void newnode(int &r,int fa,int k) {if(tot2)r = s[tot2--];else r = ++tot1;minv[r] = key[r] = k;pre[r] = fa;rev[r] = addv[r] = ch[r][0] = ch[r][1] = 0;sz[r] = 1; }void build(int &x,int l,int r,int fa) {if(l>r)return;int m = (l+r)>>1;newnode(x,fa,a[m]);build(ch[x][0],l,m-1,x);build(ch[x][1],m+1,r,x);pushup(x); }void init() {root = tot1 = tot2 = 0;pre[root] = ch[root][1] = ch[root][0] = addv[root] = key[root] = rev[root] = sz[root] = 0;minv[root] = INF;newnode(root,0,INF);newnode(ch[root][1],root,INF);build(keyv,1,n,ch[root][1]);pushup(ch[root][1]);pushup(root);}void rotate(int x,int d) {int y = pre[x];pushdown(y);pushdown(x);ch[y][!d] = ch[x][d];pre[ch[x][d] ] = y;if(pre[y]) ch[pre[y]][ch[pre[y]][1] == y] = x;pre[x] = pre[y];ch[x][d] = y;pre[y] = x;pushup(y); }void splay(int r,int goal) {while(pre[r] != goal){if(pre[pre[r]] == goal)rotate(r,ch[pre[r]][0]==r);else{int y = pre[r];int d = ch[pre[y]][0] == y;if(ch[y][d] == r){rotate(r,!d);rotate(r,d);}else{rotate(y,d);rotate(r,d);}}}pushup(r);if(goal==0)root = r; }int kth(int r,int k) {pushdown(r);int t = sz[ch[r][0]];if(t+1 == k) return r;else if(k<=t) return kth(ch[r][0],k);else return kth(ch[r][1],k-1-t); } int getmax(int r) {pushdown(r);while(ch[r][1]){r = ch[r][1];pushdown(r);}return r; }int getmin(int r) {pushdown(r);while(ch[r][0]){r = ch[r][0];pushdown(r);}return r; }/**本題*/ void add(int l,int r,int v) {splay(kth(root,l),0);splay(kth(root,r+2),root);update_add(keyv,v);pushup(ch[root][1]);pushup(root); }void Reverse(int l,int r) {splay(kth(root,l),0);splay(kth(root,r+2),root);update_rev(keyv);pushup(ch[root][1]);pushup(root); }void revolve(int l,int r,int T)///區間循環移位 {int len = r-l+1;T = (T%len);if(T==0)return;int m = r - T;/**區間[l,m],[m+1,r]調換位置*/splay(kth(root,m+1),0);splay(kth(root,r+2),root);int tmp = keyv;keyv = 0;pushup(ch[root][1]);pushup(root);///先把第二個區間刪除。splay(kth(root,l),0);splay(kth(root,l+1),root);keyv = tmp;pre[tmp] = ch[root][1];pushup(ch[root][1]);pushup(root);///再插入第一個區間前。 這樣做的前提是兩個區間是相鄰的! }void Insert(int x,int p)///插入 {splay(kth(root,x+1),0);///x后splay(kth(root,x+2),root);///x+1前newnode(keyv,ch[root][1],p);pushup(ch[root][1]);pushup(root); }void Erase(int r) {if(r){s[++tot2] = r;Erase(ch[r][0]);Erase(ch[r][1]);} }void ddelete(int r)///刪除 {splay(kth(root,r),0);splay(kth(root,r+2),root);Erase(keyv);pre[keyv] = 0;keyv = 0;pushup(ch[root][1]);pushup(root); }int mmin(int l,int r)///區間最小 {splay(kth(root,l),0);splay(kth(root,r+2),root);return minv[keyv]; } void Treavel(int x) {if(x){pushdown(x);Treavel(ch[x][0]);printf("%d ",key[x]);Treavel(ch[x][1]);} } int main() {int x,y,z;char op[20];while(scanf("%d",&n)==1){for(int i=1;i<=n;i++)scanf("%d",a+i);init();scanf("%d",&q);while(q--){scanf("%s",op);if(strcmp(op,"ADD") == 0){scanf("%d%d%d",&x,&y,&z);add(x,y,z);}else if(strcmp(op,"REVERSE")==0){scanf("%d%d",&x,&y);Reverse(x,y);}else if(strcmp(op,"REVOLVE")==0){scanf("%d%d%d",&x,&y,&z);revolve(x,y,z);}else if(strcmp(op,"DELETE")==0){scanf("%d",&x);ddelete(x);}else if(strcmp(op,"MIN")==0){scanf("%d%d",&x,&y);printf("%d\n",mmin(x,y));}else if(strcmp(op,"INSERT")==0){scanf("%d%d",&x,&y);Insert(x,y);}//Treavel(root);}} }?
總結
以上是生活随笔為你收集整理的POJ 3580 SuperMemo(伸展树的几个基本操作)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS限制字数,超出部份显示点点点...
- 下一篇: html超出后变成点点点,css多行文字