傳送門html
感受這題作下來心態有點崩……$RMQ$求$LCA$沒有樹剖快我能夠理解爲是常數太大……然而我明明用了自覺得不會退化的點分然而爲何比會退化的點分跑得反而更慢啊啊啊啊~~~ios
先膜一波zsy大佬git
講講作法。題目的要求是給定一個根$p$,求$\sum _{i=1}^ns_i^2$,其中$s_i$表示子樹中的點權和spa
咱們設$sum=\sum _{i=1}^n val_i$,即整棵樹的點權和。先考慮一下$\sum _{i=1}^ns_i$怎麼求。考慮一下每個點的貢獻,每個點都會對被計算$dep_i+1$次(其中$dep_i$表示$dist(i,p)$),那麼很顯然$\sum _{i=1}^ns_i=\sum_{i=1}^nval_i*(dep_i+1)=\sum_{i=1}^nval_i*dep_i+sum$。而後考慮一下$val_i*dep_i$,如何動態維護?->幻想鄉戰略遊戲……code
簡單來講,就是建好點分樹,而後每一次及時修改和查詢htm
而後咱們令$calc(p)$以$p$爲根時的$\sum _{i=1}^nval_i*dep_i$blog
而後考慮以下式子$$\sum_{i=1}^n\sum_{j=1}^nval_i*val_j*dist(i,j)$$遊戲
是否是能夠理解爲在全部的點對$(i,j)$之間的全部邊上加上權值$val_i*val_j$(恰好有$dist(i,j)$條邊),而後再求整棵樹的權值?get
而後咱們考慮一下每條邊的權值,確定等於兩側的子樹點權和的乘積。那麼,不管是以哪個點$p$爲根,它的權值都等於$s_i*(sum-s_i)$,其中$s_i$表示這條邊指向的兒子的子樹的點權和it
那麼,上面的式子就能夠變成這樣$$\sum_{i=1}^n\sum_{j=1}^nval_i*val_j*dist(i,j)=\sum_{i=1}^ns_i*(sum-s_i)$$
又由於上式左邊是不變的,因此無論選取哪個$p$爲根,右邊都是不變的
令$W=\sum_{i=1}^ns_i*(sum-s_i)$,而後能夠直接$O(n)dp$出$W$,而後考慮對點的修改對$W$形成的影響
$W=\sum_{i=1}^n\sum{j=1}^nval_i*val_j*dist(i,j)$,設點$u$的變化量爲$Δv$,那麼$ΔW=Δv*\sum_{j=1}^nval_j*dist(i,j)$,至關於$Δv*calc(i)$,而後能夠考慮和通常的動態點分同樣計算
而後最後詢問的答案就是$$W=\sum_{i=1}^ns_i*(sum-s_i)$$
$$\sum_{i=1}^ns_i^2=\sum_{i=1}^ns_i*sum-W$$
$$\sum_{i=1}^ns_i^2=sum(calc(i)+sum)-W$$
1 // luogu-judger-enable-o2 2 //minamoto 3 #include<iostream> 4 #include<cstdio> 5 #include<algorithm> 6 #define ll long long 7 using namespace std; 8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 9 char buf[1<<21],*p1=buf,*p2=buf; 10 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 11 inline int read(){ 12 #define num ch-'0' 13 char ch;bool flag=0;int res; 14 while(!isdigit(ch=getc())) 15 (ch=='-')&&(flag=true); 16 for(res=num;isdigit(ch=getc());res=res*10+num); 17 (flag)&&(res=-res); 18 #undef num 19 return res; 20 } 21 char sr[1<<21],z[20];int C=-1,Z; 22 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 23 inline void print(ll x){ 24 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 25 while(z[++Z]=x%10+48,x/=10); 26 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 27 } 28 const int N=200005; 29 int ver[N<<1],head[N],Next[N<<1]; 30 int val[N],fa[N],pa[N],d[N],sz[N],son[N],top[N]; 31 int n,q,tot; 32 void dfs1(int u,int fa){ 33 pa[u]=fa,d[u]=d[fa]+1,sz[u]=1; 34 for(int i=head[u];i;i=Next[i]){ 35 int v=ver[i];if(v==fa) continue; 36 dfs1(v,u); 37 sz[u]+=sz[v];if(sz[v]>sz[son[u]]) son[u]=v; 38 } 39 } 40 void dfs2(int u,int fa){ 41 top[u]=fa; 42 if(son[u]) dfs2(son[u],fa);else return; 43 for(int i=head[u];i;i=Next[i]) 44 if(ver[i]!=pa[u]&&ver[i]!=son[u]) 45 dfs2(ver[i],ver[i]); 46 } 47 int LCA(int u,int v){ 48 while(top[u]^top[v]){ 49 if(d[top[u]]<d[top[v]]) swap(u,v); 50 u=pa[top[u]]; 51 } 52 return d[u]<d[v]?u:v; 53 } 54 int dis(int u,int v){return d[u]+d[v]-(d[LCA(u,v)]<<1);} 55 int size,rt,vis[N]; 56 ll sum[N],sum1[N],sum2[N],sigma,omega,ans; 57 void getrt(int u,int fa){ 58 sz[u]=1,son[u]=0; 59 for(int i=head[u];i;i=Next[i]){ 60 int v=ver[i];if(v==fa||vis[v]) continue; 61 getrt(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]); 62 } 63 cmax(son[u],size-sz[u]); 64 if(son[u]<son[rt]) rt=u; 65 } 66 void solve(int u,int f){ 67 fa[u]=f,vis[u]=1;int totsz=size; 68 for(int i=head[u];i;i=Next[i]){ 69 int v=ver[i]; 70 if(!vis[v]){ 71 size=sz[v]>sz[rt]?totsz-sz[rt]:sz[v]; 72 rt=0; 73 getrt(v,0),solve(rt,u); 74 } 75 } 76 } 77 inline void modify(int u,int v){ 78 sum[u]+=v; 79 for(int i=u;fa[i];i=fa[i]){ 80 int dist=dis(u,fa[i]); 81 sum[fa[i]]+=v; 82 sum1[fa[i]]+=dist*v; 83 sum2[i]+=dist*v; 84 } 85 } 86 inline ll calc(int u){ 87 ll res=sum1[u]; 88 for(int i=u;fa[i];i=fa[i]){ 89 int dist=dis(fa[i],u); 90 res+=(ll)dist*(sum[fa[i]]-sum[i]); 91 res+=sum1[fa[i]]-sum2[i]; 92 } 93 return res; 94 } 95 void DP(int u,int fa){ 96 sz[u]=val[u]; 97 for(int i=head[u];i;i=Next[i]){ 98 int v=ver[i]; 99 if(v!=fa) DP(v,u),sz[u]+=sz[v]; 100 } 101 omega+=1ll*sz[u]*(sigma-sz[u]); 102 } 103 int main(){ 104 n=read(),q=read(); 105 for(int i=1;i<n;++i){ 106 int u=read(),v=read(); 107 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 108 ver[++tot]=u,Next[tot]=head[v],head[v]=tot; 109 } 110 dfs1(1,0),dfs2(1,1); 111 size=n,son[rt=0]=n+1; 112 getrt(1,0),solve(rt,0); 113 for(int i=1;i<=n;++i) 114 val[i]=read(),modify(i,val[i]),sigma+=val[i]; 115 DP(1,0); 116 while(q--){ 117 int opt=read(),x=read(); 118 if(opt&1){ 119 int y=read();y-=val[x]; 120 modify(x,y),sigma+=y,omega+=y*calc(x); 121 val[x]+=y; 122 } 123 else print((calc(x)+sigma)*sigma-omega); 124 } 125 Ot(); 126 return 0; 127 }