HDU 4453 Looploop(伸展树应用,数列环)

匿名 (未验证) 提交于 2019-12-03 00:18:01

题意:

给定一个环,和一个原点,对这个环有以下操作:

add x 操作:从队首开始的的连续k2个数都加上xֵ.

reverse 操作: 从队首开始的连续k1个数都翻转

insert x 操作:在第一个元素与第二个元素之间插入一个xֵ

delete 操作: 删除原点,新原点顺时针移动一下

move 1操作:原点逆时针移动一个

move 2操作: 原点顺时针移动一个

query 操作: 返回原点元素的值

题解:

伸展树的应用:

正常的伸展树是对数列进行操作,而本题可看作是对一个首尾相连的数列进行操作;标记源点的位置,每次addreverse的时候,只需将源点反转至根节点,把根节点左边的删除,再插入到剩余序列的尾部,然后再进行更新即可。


#include<bits/stdc++.h>  using namespace std;  const int maxn = 2e5+99; #define keyv ch[ch[root][1]][0] int pre[maxn],sz[maxn],rev[maxn],add[maxn],ch[maxn][2]; int root,tot1,key[maxn]; int tot2,s[maxn]; int tp; int n,q,k1,k2; int a[maxn];  void newnode(int &r,int fa,int k) {     if(tot2) r = s[tot2--];     else r = ++tot1;     key[r] = k;     pre[r] = fa;     add[r] = rev[r] = ch[r][0] = ch[r][1] = 0;     sz[r] = 1; }  void update_rev(int r) {     if(!r)return;     swap(ch[r][0],ch[r][1]);     rev[r]^=1; }  void update_add(int r,int v) {     if(!r)return;     key[r] += v;     add[r] += v; }   void pushup(int r) {     sz[r] = 1 + sz[ch[r][1]]+sz[ch[r][0]]; }   void pushdown(int r) {     if(add[r])     {         update_add(ch[r][0],add[r]);         update_add(ch[r][1],add[r]);         add[r] = 0;     }     if(rev[r])     {         update_rev(ch[r][0]);         update_rev(ch[r][1]);         rev[r] = 0;     } } void build(int &x,int l,int r,int fa) {     if(l>r)return;     int mid = (l+r)>>1;     newnode(x,fa,a[mid]);     build(ch[x][0],l,mid-1,x);     build(ch[x][1],mid+1,r,x);     pushup(x); }    void init() {     root = tot1=tot2 = 0;     pre[root] = sz[root] = rev[root] = add[root] = key[root] = ch[root][0] = ch[root][1] = 0;     newnode(root,0,-1);     newnode(ch[root][1],root,-1);     for(int i=0;i<n;i++)scanf("%d",a+i);     build(keyv,0,n-1,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 getkth(int r,int k) {     pushdown(r);     //cout<<1;     int t = sz[ch[r][0]]+1;     if(k==t) return r;     else if(k<t)return getkth(ch[r][0],k);     else return getkth(ch[r][1],k-t); }  void ADD(int x) {     splay(tp,0);///删除左边的     int tmp = sz[ch[root][0]]+1;     splay(getkth(root,1),0);     splay(getkth(root,tmp),root);     tmp = keyv;     keyv = 0;     pushup(ch[root][1]);     pushup(root);      ///添加至末尾     splay(getkth(root,sz[root]-1),0);     keyv = tmp;     pre[keyv] = ch[root][1];     pushup(ch[root][1]);     pushup(root);      ///更新     splay(getkth(root,1),0);     splay(getkth(root,k2+2),root);     update_add(keyv,x);     pushup(ch[root][1]);     pushup(root);      tp = getkth(root,2); }  void REVERSE() {     splay(tp,0);     int tmp = sz[ch[root][0]]+1;     splay(getkth(root,1),0);     splay(getkth(root,tmp),root);     tmp = keyv;     keyv = 0;     pushup(ch[root][1]);     pushup(root);      splay(getkth(root,sz[root]-1),0);     keyv = tmp;     pre[keyv] = ch[root][1];     pushup(ch[root][1]);     pushup(root);       splay(getkth(root,1),0);     splay(getkth(root,k1+2),root);     update_rev(keyv);     pushup(ch[root][1]);     pushup(root);      tp = getkth(root,2); }   void insert(int x) {     splay(tp,0);     int t = sz[ch[root][0]]+2;     splay(getkth(root,t),root);     newnode(keyv,ch[root][1],x);     pushup(ch[root][1]);     pushup(root); }  void DELETE() {     splay(tp,0);     int tmp = sz[ch[root][0]];     splay(getkth(root,tmp),0);     splay(getkth(root,tmp+2),root);      s[++tot2] = keyv;     keyv = 0;     pushup(ch[root][1]);     pushup(root);     ///给顺时针的下一个     if(tmp+1 == sz[root])tp = getkth(root,2);///右边没了(顺时针没了)     else tp = getkth(root,tmp+1); }  void MOVE(int x) {     if(x==1)///逆时针     {         splay(tp,0);         int t = sz[ch[root][0]];         if(t==1)t = sz[root]-1;///如果左边没了         tp = getkth(root,t);     }     else///顺时针     {         splay(tp,0);         int t = sz[ch[root][0]]+2;         if(t == sz[root])t=2;///如果右边没了         tp = getkth(root,t);     } }   int query() {     splay(tp,0);     return key[root]; }  char op[99]; int x; int main() {     int kase = 0;     while(cin>>n>>q>>k1>>k2)     {         if(!n && !q && !k1 && !k2)break;         printf("Case #%d:\n",++kase);         init();         tp = getkth(root,2);         while(q--)         {             scanf("%s",op);             if(op[0] == 'a')             {                 scanf("%d",&x);                 ADD(x);             }             else if(op[0] == 'r')             {                 REVERSE();             }             else if(op[0]=='i')             {                 scanf("%d",&x);                 insert(x);             }             else if(op[0] == 'd')                 DELETE();             else if(op[0]=='m')             {                 scanf("%d",&x);                 MOVE(x);             }             else printf("%d\n",query());         }     } }                             

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!