题目大意:
很显然是一个$LCT$题= =
操作1,2都是$LCT$基本操作,操作3打个标记即可
重点就是操作4该如何在$LCT$里维护,我们先不管期望的问题,只需要把总和$/(sum*(sum+1)/2)$即可
我们把链拎出来,摊平
每个节点的答案,就是它(左侧节点数+1)*(右侧节点数+1)*它的权值
我们在用$splay$维护动态链时,$splay$树中,我们每个节点为根的子树都能表示一条链
一个节点$x$连接了左右子节点$ls,rs$,那么,$x$子树表示的链,相当于把$ls$的链,$x$节点,$rs$的链的接在了一起
我们需要把它们的信息进行合并
发现这其实是一个卷积的形式
$splay$中,每个节点维护,子树中节点数量$sz$,子树中节点权值总和$sum$,以及$lx,rx$表示它子树中所有节点的权值*(这些节点左/右侧节点数量+1),最后一个答案数组$tx$
这几个数组在$pushup$里很好处理,建议自己推式子
关键是在$update$后,下推标记时该如何处理。我们必须保证下推标记后,子节点的$lx,rx,tx$数组能$O(1)$更新
设增加的权值是$tag$
显然$lx,rx$都会增加$tag*sz_{x}*(sz_{x}+1)/2$,把链摊开,$tag$对每个节点的贡献是一个等差数列
$tag$对答案$tx$的更新值是$\sum i\cdot(sz-i+1)$ 其中$i$表示它在摊开链中的位置
展开,再用$1~n$平方和公式,可得$tag$对答案的贡献是$tag*sz*(sz+1)*(sz+2)/6$
注意!$revers$操作需要把$lx$和$rx$交换!
另外由于操作中可能有一部分边不能连,每次都$findroot$会消耗大量时间
所以每次$findroot$后,把根转上去能大幅优化常数
还有,$namespace$跑得是真的慢..$struct$就飞快
1 #include <queue> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define N1 50100 7 #define M1 2010 8 #define S1 (N1<<1) 9 #define T1 (N1<<2) 10 #define ll long long 11 #define uint unsigned int 12 #define rint register int 13 #define ull unsigned long long 14 #define dd double 15 #define il inline 16 #define inf 1000000000 17 using namespace std; 18 19 int gint() 20 { 21 int ret=0,fh=1;char c=getchar(); 22 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 23 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 24 return ret*fh; 25 } 26 int n,m,T,type; 27 int tot; 28 struct LCT{ 29 int ch[N1][2],fa[N1],rev[N1],val[N1],tag[N1]; 30 ll lx[N1],rx[N1],tx[N1],sum[N1],sz[N1]; 31 inline int idf(int x){return ch[fa[x]][0]==x?0:1;} 32 inline int isroot(int x){return (ch[fa[x]][0]==x||ch[fa[x]][1]==x)?0:1;} 33 void revers(int x) 34 { 35 swap(ch[x][0],ch[x][1]); 36 swap(lx[ch[x][0]],rx[ch[x][0]]); 37 swap(lx[ch[x][1]],rx[ch[x][1]]); 38 rev[x]^=1; 39 } 40 void pushup(int x) 41 { 42 int ls=ch[x][0],rs=ch[x][1]; 43 sz[x]=sz[ls]+sz[rs]+1; 44 sum[x]=sum[ls]+sum[rs]+val[x]; 45 lx[x]=lx[ls]+lx[rs]+1ll*(sum[ls]+val[x])*(sz[rs]+1); 46 rx[x]=rx[ls]+rx[rs]+1ll*(sum[rs]+val[x])*(sz[ls]+1); 47 tx[x]=tx[ls]+tx[rs]+1ll*rx[ls]*(sz[rs]+1)+1ll*lx[rs]*(sz[ls]+1)+1ll*val[x]*(sz[ls]+1)*(sz[rs]+1); 48 } 49 void pushdown(int x) 50 { 51 if(rev[x]) 52 { 53 if(ch[x][0]) revers(ch[x][0]); 54 if(ch[x][1]) revers(ch[x][1]); 55 rev[x]^=1; 56 } 57 if(tag[x]) 58 { 59 int ls=ch[x][0],rs=ch[x][1]; ll w=tag[x]; 60 if(ls) 61 { 62 tag[ls]+=w,val[ls]+=w,sum[ls]+=1ll*sz[ls]*w; 63 lx[ls]+=1ll*w*(sz[ls]+1)*sz[ls]/2; 64 rx[ls]+=1ll*w*(sz[ls]+1)*sz[ls]/2; 65 tx[ls]+=1ll*sz[ls]*(sz[ls]+1)*(sz[ls]+2)/6*w; 66 } 67 if(rs) 68 { 69 tag[rs]+=w,val[rs]+=w,sum[rs]+=1ll*sz[rs]*w; 70 lx[rs]+=1ll*(sz[rs]+1)*sz[rs]/2*w; 71 rx[rs]+=1ll*(sz[rs]+1)*sz[rs]/2*w; 72 tx[rs]+=1ll*sz[rs]*(sz[rs]+1)*(sz[rs]+2)/6*w; 73 } 74 tag[x]=0; 75 } 76 } 77 void rot(int x) 78 { 79 int y=fa[x],ff=fa[y],px=idf(x),py=idf(y); 80 if(!isroot(y)) ch[ff][py]=x; fa[x]=ff; 81 fa[ch[x][px^1]]=y,ch[y][px]=ch[x][px^1]; 82 ch[x][px^1]=y,fa[y]=x; 83 pushup(y),pushup(x); 84 } 85 int stk[N1],tp; 86 void splay(int x) 87 { 88 int y=x; stk[++tp]=x; 89 while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];} 90 while(tp){pushdown(stk[tp--]);} 91 while(!isroot(x)) 92 { 93 y=fa[x]; 94 if(isroot(y)) rot(x); 95 else if(idf(y)==idf(x)) rot(y),rot(x); 96 else rot(x),rot(x); 97 } 98 } 99 void access(int x) 100 { 101 for(int y=0;x;y=x,x=fa[x]) 102 splay(x),ch[x][1]=y,pushup(x); 103 } 104 void mkroot(int x) 105 { 106 access(x),splay(x),revers(x); 107 swap(lx[x],rx[x]); 108 } 109 int fdroot(int x) 110 { 111 access(x),splay(x); 112 while(ch[x][0]) x=ch[x][0],pushdown(x); 113 splay(x); return x; 114 } 115 void split(int x,int y){mkroot(x),access(y),splay(y);} 116 void link(int x,int y) 117 { 118 mkroot(x); 119 if(fdroot(y)!=x) fa[x]=y; 120 } 121 void cut(int x,int y) 122 { 123 split(x,y); 124 if(!ch[x][1]&&fa[x]==y&&ch[y][0]==x) 125 ch[y][0]=fa[x]=0,pushup(y); 126 } 127 ll query(int x,int y) 128 { 129 split(x,y); 130 if(fdroot(y)!=x) return -1; 131 return tx[x]; 132 } 133 void update(int x,int y,int w) 134 { 135 split(x,y); 136 if(fdroot(y)!=x) return; 137 tag[x]+=w,val[x]+=w,sum[x]+=1ll*w*sz[x]; 138 lx[x]+=1ll*w*(sz[x]+1)*sz[x]/2; 139 rx[x]+=1ll*w*(sz[x]+1)*sz[x]/2; 140 tx[x]+=1ll*sz[x]*(sz[x]+1)*(sz[x]+2)/6*w; 141 } 142 void init(){for(int i=1;i<=n;i++) sz[i]=1,pushup(i);} 143 }lct; 144 ll gcd(ll x,ll y){if(!y) return x; return gcd(y,x%y);} 145 146 int main() 147 { 148 int i,j,x,y,w,fl;ll ans,g,nn; 149 scanf("%d%d",&n,&m); 150 for(i=1;i<=n;i++) lct.val[i]=gint(); 151 lct.init(); 152 for(j=1;j<n;j++) x=gint(), y=gint(), lct.link(x,y); 153 for(j=1;j<=m;j++) 154 { 155 fl=gint(); x=gint(); y=gint(); 156 if(fl==1) lct.cut(x,y); 157 if(fl==2) lct.link(x,y); 158 if(fl==3) w=gint(),lct.update(x,y,w); 159 if(fl==4) 160 { 161 ans=lct.query(x,y); 162 if(ans==-1) {puts("-1");continue;} 163 nn=1ll*(lct.sz[x])*(lct.sz[x]+1)/2; 164 g=gcd(ans,nn); 165 printf("%lld/%lld\n",ans/g,nn/g); 166 } 167 } 168 return 0; 169 }