洛谷 P3203 [HNOI2010]弹飞绵羊 || bzoj2002

看来这个lct板子的确没什么问题

好像还可以分块做

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 typedef long long LL;
  5 namespace LCT
  6 {
  7 struct Node
  8 {
  9     Node *ch[2],*fa;
 10     bool rev;
 11     LL sz;
 12     void upd()
 13     {
 14         sz=(ch[0]?ch[0]->sz:0)+(ch[1]?ch[1]->sz:0)+1;
 15     }
 16     void pd()
 17     {
 18         if(rev)
 19         {
 20             swap(ch[0],ch[1]);
 21             if(ch[0])    ch[0]->rev^=1;
 22             if(ch[1])    ch[1]->rev^=1;
 23             rev=0;
 24         }
 25     }
 26 }nodes[300100];
 27 LL mem;
 28 Node *getnode()
 29 {
 30     return nodes+(mem++);
 31 }
 32 bool isroot(Node *x)
 33 {
 34     return (!x->fa)||((x->fa->ch[0]!=x)&&(x->fa->ch[1]!=x));
 35 }
 36 bool gson(Node *o)    {return o==o->fa->ch[1];}//获得是父亲的左儿子(返回0)还是右儿子(1),要求保证存在父亲
 37 void rotate(Node *o,bool d)
 38 //在o子树中执行d=0左旋,d=1右旋,在旋转前不标记下传,并将o父节点的对应子节点由o变为需要值,要求保证存在子树(!d)
 39 {
 40     Node *k=o->ch[!d];if(!isroot(o))    o->fa->ch[gson(o)]=k;//注意这一句修改o父节点的要写在前面,曾经出过错调了一会
 41     o->ch[!d]=k->ch[d];k->ch[d]=o;
 42     o->upd();k->upd();
 43     k->fa=o->fa;o->fa=k;if(o->ch[!d])    o->ch[!d]->fa=o;
 44 }
 45 Node *st[300100];LL top;
 46 void solvetag(Node *o)
 47 {
 48     while(!isroot(o))    st[++top]=o,o=o->fa;
 49     st[++top]=o;
 50     while(top)    st[top--]->pd();
 51 }
 52 void splay(Node *o)
 53 {
 54     solvetag(o);
 55     Node *fa,*fafa;bool d1,d2;
 56     while(!isroot(o))
 57     {
 58         fa=o->fa;d1=(o==fa->ch[0]);
 59         if(isroot(fa))    rotate(fa,d1);
 60         else
 61         {
 62             fafa=o->fa->fa;d2=(fa==fafa->ch[0]);//要保证fa不是root之后才能获取这两个值,曾错过
 63             if(d1==d2)    rotate(fafa,d1),rotate(fa,d1);//zig-zig,两次相同方向的单旋,先把父亲转上去,再把自己转上去
 64             else    rotate(fa,d1),rotate(fafa,d2);//zig-zag,两次相反方向的单旋,连续两次把自己转上去
 65         }
 66     }
 67 }
 68 void access(Node *o)
 69 {
 70     for(Node *lst=NULL;o;lst=o,o=o->fa)
 71     {
 72         splay(o);//此处不pushdown是由于splay中保证进行过了
 73         o->ch[1]=lst;o->upd();//注意upd
 74     }
 75 }
 76 Node *gtop(Node *o)
 77 {
 78     access(o);splay(o);
 79     for(;o->ch[0];o=o->ch[0],o->pd());//此处不在开始前pushdown(o)是由于splay中保证进行过了
 80     splay(o);return o;//听说这里不splay一下也很难卡掉
 81 }
 82 void mtop(Node *o)    {access(o);splay(o);o->rev^=1;}
 83 void link(Node *x,Node *y)
 84 {
 85     if(gtop(x)==gtop(y))    return;
 86     mtop(y);y->fa=x;
 87 }
 88 void cut(Node *x,Node *y)
 89 {
 90     mtop(x);access(y);splay(y);
 91     if(y->ch[0]!=x||x->ch[1])    return;//如果x、y之间直接有边,那么上面一行的操作之后应当是x与y在单独一棵splay中,那么一定保证y左子节点是x且x没有右子节点
 92     x->fa=y->ch[0]=NULL;//注意,改的是x的父亲和y的子节点(虽然x的确是树的根,但是此时在splay上是y的子节点,不能搞混)
 93     y->upd();//注意
 94 }
 95 LL query(Node *x,Node *y)
 96 {
 97     mtop(x);access(y);splay(y);
 98     //if(gtop(y)!=x)    return 0;//此题保证x与y连通,不需要
 99     return y->sz;
100 }
101 }
102 LCT::Node *nd[300100];
103 LL n,m;char tmp[20];LL a[300100];
104 int main()
105 {
106     LL i,x,y,idx;
107     scanf("%lld",&n);
108     for(i=0;i<=n;i++)
109     {
110         nd[i]=LCT::getnode();
111         nd[i]->sz=1;
112     }
113     for(i=0;i<n;i++)
114     {
115         scanf("%lld",&a[i]);
116         LCT::link(nd[i],nd[min(i+a[i],n)]);
117     }
118     scanf("%lld",&m);
119     for(i=1;i<=m;i++)
120     {
121         scanf("%lld%lld",&idx,&x);
122         if(idx==1)
123         {
124             printf("%lld\n",LCT::query(nd[x],nd[n])-1);
125         }
126         else
127         {
128             scanf("%lld",&y);
129             LCT::cut(nd[x],nd[min(x+a[x],n)]);
130             a[x]=y;
131             LCT::link(nd[x],nd[min(x+a[x],n)]);
132         }
133     }
134     return 0;
135 }

 

posted @ 2018-04-19 20:07  hehe_54321  阅读(95)  评论(0编辑  收藏
AmazingCounters.com