【题目链接】
【题意】
给定一棵树,提供树上路径乘/加一个数,加边断边,查询路径和的操作。
【思路】
LCT+传标
一次dfs构造LCT。
LCT维护信息:v,sum,rev,add,mul,siz
提取路径(u,v):evert(u)->Access(v),splay(v),此时以v为根的splay辅助树即u->v的路径,直接进行操作即可。
关于下传标记:
对于一个节点的标记,始终保持该标记已作用在该节点上。
给节点打标记后作用于该节点,每次传标,给儿子打上标记且作用于该儿子。
对于覆盖类标记,直接覆盖即可。反转标记单独处理。
对于非覆盖类标记,考虑操作先后:先下传乘法标记,然后下传加法标记。对于乘法下传,还需要作用在加法标记上。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define FOR(a,b,c) for(int a=b;a<=c;a++) 5 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 6 using namespace std; 7 8 typedef long long ll; 9 typedef unsigned int ul; 10 const int N = 4e5+10; 11 const int MOD = 51061; 12 13 namespace LCT { 14 15 struct Node { 16 Node *ch[2],*fa; 17 ul v,siz,rev,add,mul,sum; 18 Node() ; 19 //给当前结点打上标记 且更新当前结点 20 void mulv(int x) { 21 mul=(mul*x)%MOD; 22 v=(v*x)%MOD; 23 add=(add*x)%MOD; 24 sum=(sum*x)%MOD; 25 } 26 void addv(int x) { 27 v=(v+x)%MOD; 28 add=(add+x)%MOD; 29 sum=(sum+siz*x)%MOD; 30 } 31 void reverse() { 32 rev^=1; 33 swap(ch[0],ch[1]); 34 } 35 //up push down 36 void up_push() { 37 if(fa->ch[0]==this||fa->ch[1]==this) 38 fa->up_push(); 39 if(mul^1) { //mul != 1 40 ch[0]->mulv(mul); 41 ch[1]->mulv(mul); 42 mul=1; 43 } 44 if(add) { 45 ch[0]->addv(add); 46 ch[1]->addv(add); 47 add=0; 48 } 49 if(rev) { 50 ch[0]->reverse(); 51 ch[1]->reverse(); 52 rev=0; 53 } 54 } 55 void maintain() { 56 siz=ch[0]->siz+ch[1]->siz+1; 57 sum=(ch[0]->sum+ch[1]->sum+v)%MOD; 58 } 59 } *null=new Node, T[N]; 60 Node:: Node() { 61 fa=ch[0]=ch[1]=null; 62 add=rev=0,mul=siz=1; 63 sum=v=0; 64 } 65 66 void rot(Node* o,int d) { 67 Node *p=o->fa; 68 p->ch[d]=o->ch[d^1]; 69 o->ch[d^1]->fa=p; 70 o->ch[d^1]=p; 71 o->fa=p->fa; 72 if(p==p->fa->ch[0]) 73 p->fa->ch[0]=o; 74 else if(p==p->fa->ch[1]) 75 p->fa->ch[1]=o; 76 p->fa=o; 77 p->maintain(); 78 } 79 void splay(Node* o) { 80 o->up_push(); 81 Node *nf,*nff; 82 while(o->fa->ch[0]==o||o->fa->ch[1]==o) { 83 nf=o->fa,nff=nf->fa; 84 if(o==nf->ch[0]) { 85 if(nf==nff->ch[0]) rot(nf,0); 86 rot(o,0); 87 } else { 88 if(nf==nff->ch[1]) rot(nf,1); 89 rot(o,1); 90 } 91 } 92 o->maintain(); 93 } 94 void Access(Node* o) { 95 Node* son=null; 96 while(o!=null) { 97 splay(o); 98 o->ch[1]=son; 99 o->maintain(); 100 son=o; o=o->fa; 101 } 102 } 103 void evert(Node* o) { 104 Access(o); 105 splay(o); 106 o->reverse(); 107 } 108 void Link(Node *u,Node *v) { 109 evert(u); 110 u->fa=v; 111 } 112 void Cut(Node *u,Node *v) { 113 evert(u); 114 Access(v); splay(v); 115 u->fa=v->ch[0]=null; 116 v->maintain(); 117 } 118 119 } 120 using namespace LCT; 121 122 struct Edge { int v,nxt; 123 }e[N<<2]; 124 int en=1,front[N]; 125 void adde(int u,int v) { 126 e[++en]=(Edge){v,front[u]}; front[u]=en; 127 } 128 129 ll read() 130 { 131 char c=getchar(); 132 ll f=1,x=0; 133 while(!isdigit(c)) { 134 if(c=='-') f=-1; 135 c=getchar(); 136 } 137 while(isdigit(c)) 138 x=x*10+c-'0', 139 c=getchar(); 140 return x*f; 141 } 142 143 int n,q; 144 145 void build(int u,int fa) { 146 T[u].sum=T[u].v=1; 147 trav(u,i) { 148 int v=e[i].v; 149 if(v!=fa) { 150 T[v].fa=&T[u]; 151 build(v,u); 152 } 153 } 154 } 155 156 int main() 157 { 158 null->siz=null->mul=0; 159 n=read(),q=read(); 160 for(int i=1;i<n;i++) { 161 int u=read(),v=read(); 162 adde(u,v),adde(v,u); 163 } 164 build(1,-1); 165 char op[2]; 166 int u,v,x,y; 167 while(q--) { 168 scanf("%s",&op); 169 u=read(),v=read(); 170 if(op[0]=='+' || op[0]=='*') { 171 x=read(); 172 evert(&T[u]); 173 Access(&T[v]); splay(&T[v]); 174 if(op[0]=='+') T[v].addv(x); 175 else T[v].mulv(x); 176 } else 177 if(op[0]=='-') { 178 x=read(),y=read(); 179 Cut(&T[u],&T[v]); 180 Link(&T[x],&T[y]); 181 } else { 182 evert(&T[u]); 183 Access(&T[v]); splay(&T[v]); 184 printf("%d ",T[v].sum); 185 } 186 } 187 return 0; 188 }