洛谷 P1501 [国家集训队]Tree II
Posted 哈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1501 [国家集训队]Tree II相关的知识,希望对你有一定的参考价值。
看来这个LCT板子并没有什么问题
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long LL; 5 const LL md=51061; 6 namespace LCT 7 { 8 struct Node 9 { 10 Node *ch[2],*fa; 11 bool rev; 12 LL addv,mulv; 13 LL dat,sum,sz; 14 void padd(LL x) 15 { 16 addv=(addv+x)%md;dat=(dat+x)%md;sum=(sum+x*sz)%md; 17 } 18 void pmul(LL x) 19 { 20 addv=addv*x%md;mulv=mulv*x%md;dat=dat*x%md;sum=sum*x%md; 21 } 22 void upd() 23 { 24 sum=((ch[0]?ch[0]->sum:0)+(ch[1]?ch[1]->sum:0)+dat)%md; 25 sz=(ch[0]?ch[0]->sz:0)+(ch[1]?ch[1]->sz:0)+1; 26 } 27 void pd() 28 { 29 if(rev) 30 { 31 swap(ch[0],ch[1]); 32 if(ch[0]) ch[0]->rev^=1; 33 if(ch[1]) ch[1]->rev^=1; 34 rev=0; 35 } 36 if(mulv!=1) 37 { 38 if(ch[0]) ch[0]->pmul(mulv); 39 if(ch[1]) ch[1]->pmul(mulv); 40 mulv=1; 41 } 42 if(addv) 43 { 44 if(ch[0]) ch[0]->padd(addv); 45 if(ch[1]) ch[1]->padd(addv); 46 addv=0; 47 } 48 } 49 }nodes[300100]; 50 LL mem; 51 Node *getnode() 52 { 53 return nodes+(mem++); 54 } 55 bool isroot(Node *x) 56 { 57 return (!x->fa)||((x->fa->ch[0]!=x)&&(x->fa->ch[1]!=x)); 58 } 59 bool gson(Node *o) {return o==o->fa->ch[1];}//获得是父亲的左儿子(返回0)还是右儿子(1),要求保证存在父亲 60 void rotate(Node *o,bool d) 61 //在o子树中执行d=0左旋,d=1右旋,在旋转前不标记下传,并将o父节点的对应子节点由o变为需要值,要求保证存在子树(!d) 62 { 63 Node *k=o->ch[!d];if(!isroot(o)) o->fa->ch[gson(o)]=k;//注意这一句修改o父节点的要写在前面,曾经出过错调了一会 64 o->ch[!d]=k->ch[d];k->ch[d]=o; 65 o->upd();k->upd(); 66 k->fa=o->fa;o->fa=k;if(o->ch[!d]) o->ch[!d]->fa=o; 67 } 68 Node *st[300100];LL top; 69 void solvetag(Node *o) 70 { 71 while(!isroot(o)) st[++top]=o,o=o->fa; 72 st[++top]=o; 73 while(top) st[top--]->pd(); 74 } 75 void splay(Node *o) 76 { 77 solvetag(o); 78 Node *fa,*fafa;bool d1,d2; 79 while(!isroot(o)) 80 { 81 fa=o->fa;d1=(o==fa->ch[0]); 82 if(isroot(fa)) rotate(fa,d1); 83 else 84 { 85 fafa=o->fa->fa;d2=(fa==fafa->ch[0]);//要保证fa不是root之后才能获取这两个值,曾错过 86 if(d1==d2) rotate(fafa,d1),rotate(fa,d1);//zig-zig,两次相同方向的单旋,先把父亲转上去,再把自己转上去 87 else rotate(fa,d1),rotate(fafa,d2);//zig-zag,两次相反方向的单旋,连续两次把自己转上去 88 } 89 } 90 } 91 void access(Node *o) 92 { 93 for(Node *lst=NULL;o;lst=o,o=o->fa) 94 { 95 splay(o);//此处不pushdown是由于splay中保证进行过了 96 o->ch[1]=lst;o->upd();//注意upd 97 } 98 } 99 Node *gtop(Node *o) 100 { 101 access(o);splay(o); 102 for(;o->ch[0];o=o->ch[0],o->pd());//此处不在开始前pushdown(o)是由于splay中保证进行过了 103 splay(o);return o;//听说这里不splay一下也很难卡掉 104 } 105 void mtop(Node *o) {access(o);splay(o);o->rev^=1;} 106 void link(Node *x,Node *y) 107 { 108 if(gtop(x)==gtop(y)) return; 109 mtop(y);y->fa=x; 110 } 111 void cut(Node *x,Node *y) 112 { 113 mtop(x);access(y);splay(y); 114 if(y->ch[0]!=x||x->ch[1]) return;//如果x、y之间直接有边,那么上面一行的操作之后应当是x与y在单独一棵splay中,那么一定保证y左子节点是x且x没有右子节点 115 x->fa=y->ch[0]=NULL;//注意,改的是x的父亲和y的子节点(虽然x的确是树的根,但是此时在splay上是y的子节点,不能搞混) 116 y->upd();//注意 117 } 118 LL query(Node *x,Node *y) 119 { 120 mtop(x);access(y);splay(y); 121 //if(gtop(y)!=x) return 0;//此题保证x与y连通,不需要 122 return y->sum; 123 } 124 void add(Node *x,Node *y,LL t) 125 { 126 mtop(x);access(y);splay(y); 127 y->padd(t); 128 } 129 void mul(Node *x,Node *y,LL t) 130 { 131 mtop(x);access(y);splay(y); 132 y->pmul(t); 133 } 134 } 135 LCT::Node *nd[300100]; 136 LL n,q;char tmp[20]; 137 int main() 138 { 139 LL i,x,y,t,x2,y2; 140 scanf("%lld%lld",&n,&q); 141 for(i=1;i<=n;i++) 142 { 143 nd[i]=LCT::getnode(); 144 nd[i]->mulv=1;nd[i]->dat=nd[i]->sum=1;nd[i]->sz=1; 145 } 146 for(i=1;i<n;i++) 147 { 148 scanf("%lld%lld",&x,&y); 149 LCT::link(nd[x],nd[y]); 150 } 151 while(q--) 152 { 153 scanf("%s",tmp); 154 switch(tmp[0]) 155 { 156 case ‘+‘: 157 scanf("%lld%lld%lld",&x,&y,&t); 158 LCT::add(nd[x],nd[y],t); 159 break; 160 case ‘-‘: 161 scanf("%lld%lld%lld%lld",&x,&y,&x2,&y2); 162 LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]); 163 break; 164 case ‘*‘: 165 scanf("%lld%lld%lld",&x,&y,&t); 166 LCT::mul(nd[x],nd[y],t); 167 break; 168 case ‘/‘: 169 scanf("%lld%lld",&x,&y); 170 printf("%lld\n",LCT::query(nd[x],nd[y])); 171 } 172 } 173 return 0; 174 }
压行后:
1 #pragma GCC optimize("Ofast") 2 #pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector") 3 #pragma GCC diagnostic error "-fwhole-program" 4 #pragma GCC diagnostic error "-fcse-skip-blocks" 5 #pragma GCC diagnostic error "-funsafe-loop-optimizations" 6 #pragma GCC diagnostic error "-std=c++14" 7 #include<cstdio> 8 #include<algorithm> 9 using namespace std; 10 typedef long long LL; 11 const LL md=51061; 12 namespace LCT 13 { 14 struct Node 15 { 16 Node *ch[2],*fa; 17 bool rev; 18 LL addv,mulv; 19 LL dat,sum,sz; 20 void padd(LL x) 21 { 22 addv=(addv+x)%md;dat=(dat+x)%md;sum=(sum+x*sz)%md; 23 } 24 void pmul(LL x) 25 { 26 addv=addv*x%md;mulv=mulv*x%md;dat=dat*x%md;sum=sum*x%md; 27 } 28 void upd() 29 { 30 sum=((ch[0]?ch[0]->sum:0)+(ch[1]?ch[1]->sum:0)+dat)%md; 31 sz=(ch[0]?ch[0]->sz:0)+(ch[1]?ch[1]->sz:0)+1; 32 } 33 void pd() 34 { 35 if(rev) 36 { 37 swap(ch[0],ch[1]); 38 if(ch[0]) ch[0]->rev^=1; 39 if(ch[1]) ch[1]->rev^=1; 40 rev=0; 41 } 42 if(mulv!=1) 43 { 44 if(ch[0]) ch[0]->pmul(mulv); 45 if(ch[1]) ch[1]->pmul(mulv); 46 mulv=1; 47 } 48 if(addv) 49 { 50 if(ch[0]) ch[0]->padd(addv); 51 if(ch[1]) ch[1]->padd(addv); 52 addv=0; 53 } 54 } 55 }nodes[300100]; 56 LL mem; 57 Node *getnode() 58 { 59 return nodes+(mem++); 60 } 61 bool isroot(Node *x) 62 { 63 return (!x->fa)||((x->fa->ch[0]!=x)&&(x->fa->ch[1]!=x)); 64 } 65 bool gson(Node *o) {return o==o->fa->ch[1];}//获得是父亲的左儿子(返回0)还是右儿子(1),要求保证存在父亲 66 void rotate(Node *o,bool d) 67 //在o子树中执行d=0左旋,d=1右旋,在旋转前不标记下传,并将o父节点的对应子节点由o变为需要值,要求保证存在子树(!d) 68 { 69 Node *k=o->ch[!d];if(!isroot(o)) o->fa->ch[gson(o)]=k;//注意这一句修改o父节点的要写在前面,曾经出过错调了一会 70 o->ch[!d]=k->ch[d];k->ch[d]=o; 71 o->upd();k->upd(); 72 k->fa=o->fa;o->fa=k;if(o->ch[!d]) o->ch[!d]->fa=o; 73 } 74 Node *st[300100];LL top; 75 void solvetag(Node *o) 76 { 77 while(!isroot(o)) st[++top]=o,o=o->fa; 78 st[++top]=o; 79 while(top) st[top--]->pd(); 80 } 81 void splay(Node *o) 82 { 83 solvetag(o); 84 Node *fa,*fafa;bool d1,d2; 85 while(!isroot(o)) 86 { 87 fa=o->fa;d1=(o==fa->ch[0]); 88 if(isroot(fa)) rotate(fa,d1); 89 else 90 { 91 fafa=o->fa->fa;d2=(fa==fafa->ch[0]);//要保证fa不是root之后才能获取这两个值,曾错过 92 if(d1==d2) rotate(fafa,d1),rotate(fa,d1);//zig-zig,两次相同方向的单旋,先把父亲转上去,再把自己转上去 93 else rotate(fa,d1),rotate(fafa,d2);//zig-zag,两次相反方向的单旋,连续两次把自己转上去 94 } 95 } 96 } 97 void access(Node *o) 98 { 99 for(Node *lst=NULL;o;lst=o,o=o->fa) 100 { 101 splay(o); 102 o->ch[1]=lst;o->upd(); 103 } 104 } 105 Node *gtop(Node *o) 106 { 107 access(o);splay(o); 108 for(;o->ch[0];o=o->ch[0],o->pd()); 109 splay(o);return o; 110 } 111 void mtop(Node *o) {access(o);splay(o);o->rev^=1;} 112 void split(Node *x,Node *y) {mtop(x);access(y);splay(y);} 113 void link(Node *x,Node *y) {mtop(y);y->fa=x;} 114 void cut(Node *x,Node *y) {split(x,y);x->fa=y->ch[0]=NULL;y->upd();} 115 LL query(Node *x,Node *y) {split(x,y);return y->sum;} 116 void add(Node *x,Node *y,LL t) {split(x,y);y->padd(t);} 117 void mul(Node *x,Node *y,LL t) {split(x,y);y->pmul(t);} 118 } 119 LCT::Node *nd[300100]; 120 LL n,q;char tmp[20]; 121 int main() 122 { 123 LL i,x,y,t,x2,y2; 124 scanf("%lld%lld",&n,&q); 125 for(i=1;i<=n;i++) 126 { 127 nd[i]=LCT::getnode(); 128 nd[i]->mulv=1;nd[i]->dat=nd[i]->sum=1;nd[i]->sz=1; 129 } 130 for(i=1;i<n;i++) 131 { 132 scanf("%lld%lld",&x,&y); 133 LCT::link(nd[x],nd[y]); 134 } 135 while(q--) 136 { 137 scanf("%s",tmp); 138 switch(tmp[0]) 139 { 140 case ‘+‘: 141 scanf("%lld%lld%lld",&x,&y,&t); 142 LCT::add(nd[x],nd[y],t); 143 break; 144 case ‘-‘: 145 scanf("%lld%lld%lld%lld",&x,&y,&x2,&y2); 146 LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]); 147 break; 148 case ‘*‘: 149 scanf("%lld%lld%lld",&x,&y,&t); 150 LCT::mul(nd[x],nd[y],t); 151 break; 152 case ‘/‘: 153 scanf("%lld%lld",&x,&y); 154 printf("%lld\n",LCT::query(nd[x],nd[y])); 155 } 156 } 157 return 0; 158 }
以上是关于洛谷 P1501 [国家集训队]Tree II的主要内容,如果未能解决你的问题,请参考以下文章