洛谷 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 }
重新打了一个板子
1 #include<cstdio> 2 #include<algorithm> 3 #include<cassert> 4 #define md 51061 5 using namespace std; 6 typedef long long LL; 7 int Add(int a,int b) {return (a+b)%md;} 8 int Add(int a,int b,int c) {return (a+b+c)%md;} 9 int Mul(int a,int b) {return LL(a)*b%md;} 10 namespace LCT 11 { 12 const int N=100000; 13 struct Node 14 { 15 Node *ch[2],*fa; 16 bool rev; 17 int addv,mulv; 18 int dat,sum,sz; 19 void upd() 20 { 21 sum=Add((ch[0]?ch[0]->sum:0),dat,(ch[1]?ch[1]->sum:0)); 22 sz=(ch[0]?ch[0]->sz:0)+1+(ch[1]?ch[1]->sz:0); 23 } 24 void padd(int x) {addv=Add(addv,x);dat=Add(dat,x);sum=Add(sum,Mul(x,sz));} 25 void pmul(int x) {addv=Mul(addv,x);mulv=Mul(mulv,x);dat=Mul(dat,x);sum=Mul(sum,x);} 26 void pd() 27 { 28 if(rev) 29 { 30 swap(ch[0],ch[1]); 31 if(ch[0]) ch[0]->rev^=1; 32 if(ch[1]) ch[1]->rev^=1; 33 rev=0; 34 } 35 if(mulv!=1) 36 { 37 if(ch[0]) ch[0]->pmul(mulv); 38 if(ch[1]) ch[1]->pmul(mulv); 39 mulv=1; 40 } 41 if(addv) 42 { 43 if(ch[0]) ch[0]->padd(addv); 44 if(ch[1]) ch[1]->padd(addv); 45 addv=0; 46 } 47 } 48 bool isroot() {return (!fa)||(this!=fa->ch[0]&&this!=fa->ch[1]);} 49 bool gson() {return this==fa->ch[1];} 50 void rot()//将自身向上旋,要求已经完成下传标记 51 { 52 bool d=gson();Node *f=fa; 53 fa=f->fa;if(!f->isroot()) f->fa->ch[f->gson()]=this; 54 f->ch[d]=ch[!d];if(ch[!d]) ch[!d]->fa=f; 55 f->fa=this;ch[!d]=f; 56 f->upd();upd(); 57 } 58 }nodes[N+100]; 59 Node *st[N+100];int top; 60 int mem; 61 Node *getnode() 62 { 63 Node *t=nodes+mem++;t->mulv=1;t->sz=1;t->dat=t->sum=1; 64 return t; 65 } 66 void solvetag(Node *o) 67 { 68 while(!o->isroot()) st[++top]=o,o=o->fa; 69 st[++top]=o; 70 while(top) st[top--]->pd(); 71 } 72 void splay(Node *o) 73 { 74 solvetag(o); 75 for(;!o->isroot();o->rot()) 76 if(!o->fa->isroot()) 77 o->gson()==o->fa->gson()?o->fa->rot():o->rot(); 78 } 79 void acc(Node *o) 80 { 81 for(Node *lst=0;o;lst=o,o=o->fa) 82 splay(o),o->ch[1]=lst,o->upd(); 83 } 84 void mtop(Node *o) {acc(o);splay(o);o->rev^=1;} 85 void link(Node *x,Node *y) {mtop(y);y->fa=x;} 86 void cut(Node *x,Node *y) {mtop(x);acc(y);splay(y);x->fa=y->ch[0]=0;y->upd();} 87 int query(Node *x,Node *y) {mtop(x);acc(y);splay(y);return y->sum;} 88 void add(Node *x,Node *y,int t) {mtop(x);acc(y);splay(y);y->padd(t);} 89 void mul(Node *x,Node *y,int t) {mtop(x);acc(y);splay(y);y->pmul(t);} 90 } 91 LCT::Node *nd[100100]; 92 int n,q;char tmp[20]; 93 int main() 94 { 95 int i,x,y,t,x2,y2; 96 scanf("%d%d",&n,&q); 97 for(i=1;i<=n;i++) nd[i]=LCT::getnode(); 98 for(i=1;i<n;i++) 99 { 100 scanf("%d%d",&x,&y); 101 LCT::link(nd[x],nd[y]); 102 } 103 while(q--) 104 { 105 scanf("%s",tmp); 106 switch(tmp[0]) 107 { 108 case '+': 109 scanf("%d%d%d",&x,&y,&t); 110 LCT::add(nd[x],nd[y],t); 111 break; 112 case '-': 113 scanf("%d%d%d%d",&x,&y,&x2,&y2); 114 LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]); 115 break; 116 case '*': 117 scanf("%d%d%d",&x,&y,&t); 118 LCT::mul(nd[x],nd[y],t); 119 break; 120 case '/': 121 scanf("%d%d",&x,&y); 122 printf("%d\n",LCT::query(nd[x],nd[y])); 123 } 124 } 125 return 0; 126 }