洛谷P3676--小清新資料結構題
阿新 • • 發佈:2018-12-12
題目
今天做了一天的LINK-CUT-TREE,非常難受
晚上就只好做點小清新資料結構玩
其實晚上看了半天沒看懂,機房dalao隨手講了一下我便恍然大悟
這道題就是一道很裸很裸的鏈剖,甚至比正常的模版還要水
但是公式十分難推
考慮換根的時候,原來的根(預設為1)到這個根路徑以外的點的貢獻是不變的
那麼對於路徑上的點的貢獻,洛谷題解的第三篇就講的很清楚了
所以就貼程式碼了
// luogu-judger-enable-o2 #include<bits/stdc++.h> using namespace std; struct node { node *ls,*rs; long long sum; int tag; }pool[3200005],*tail=pool,*root; long long sum[200005],ans; int to[400005],nxt[400005],head[200005]; int size[200005],point[200005],que[200005],dfs_num; int father[200005],depth[200005],shu1,shu2,shu3; int n,q,tot,son[200005],top[200005],in[200005],real_sum; void add(int x,int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } void pushdown(node *nd,int l,int r) { if(nd->tag) { int mid=(l+r)>>1; nd->ls->tag+=nd->tag; nd->rs->tag+=nd->tag; nd->ls->sum+=1ll*(mid-l+1)*nd->tag; nd->rs->sum+=1ll*(r-mid)*nd->tag; nd->tag=0; } } void update(node *nd) { nd->sum=nd->ls->sum+nd->rs->sum; } void dfs1(int x,int fa) { size[x]=1; sum[x]=point[x]; for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==fa) continue; depth[y]=depth[x]+1; dfs1(y,x); sum[x]+=sum[y]; size[x]+=size[y]; father[y]=x; if(size[y]>size[son[x]]) son[x]=y; } ans+=1ll*sum[x]*sum[x]; } void dfs2(int x,int fa,int wow) { top[x]=wow; que[++dfs_num]=x; in[x]=dfs_num; if(son[x]) dfs2(son[x],x,wow); for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==fa||y==son[x]) continue; dfs2(y,x,y); } } void build(node *&nd,int l,int r) { nd=tail++; if(l==r) { nd->sum=sum[que[l]]; return; } int mid=(l+r)>>1; build(nd->ls,l,mid); build(nd->rs,mid+1,r); update(nd); } void modify(node *&nd,int l,int r,int L,int R,int delta) { if(l>=L&&r<=R) { nd->sum+=(r-l+1)*delta; nd->tag+=delta; return; } int mid=(l+r)>>1; pushdown(nd,l,r); if(mid>=L) modify(nd->ls,l,mid,L,R,delta); if(mid<R) modify(nd->rs,mid+1,r,L,R,delta); update(nd); } long long query(node *nd,int l,int r,int L,int R) { if(l>=L&&r<=R) { return nd->sum; } int mid=(l+r)>>1; pushdown(nd,l,r); long long ans=0; if(mid>=L) ans+=query(nd->ls,l,mid,L,R); if(mid<R) ans+=query(nd->rs,mid+1,r,L,R); return ans; } void modify(int x,int y) { int len=0; long long now=0; while(x) { now+=query(root,1,n,in[top[x]],in[x]); modify(root,1,n,in[top[x]],in[x],y); len+=depth[x]-depth[top[x]]+1; x=father[top[x]]; } ans+=1ll*len*y*y+2*y*now; } long long ask(int x) { long long now=0; int len=0; while(x) { now+=query(root,1,n,in[top[x]],in[x]); len+=depth[x]-depth[top[x]]+1; x=father[top[x]]; } return ans+1ll*(len-1)*real_sum*real_sum-1ll*real_sum*2*(now-real_sum); } int main() { cin>>n>>q; for(int i=1;i<=n-1;i++) { scanf("%d%d",&shu1,&shu2); add(shu1,shu2); add(shu2,shu1); } for(int i=1;i<=n;i++) scanf("%d",&point[i]); dfs1(1,1); dfs2(1,1,1); build(root,1,n); real_sum=sum[1]; for(int i=1;i<=q;i++) { scanf("%d",&shu1); if(shu1==1) { scanf("%d%d",&shu2,&shu3); modify(shu2,shu3-point[shu2]); real_sum+=shu3-point[shu2]; point[shu2]=shu3; } else { scanf("%d",&shu2); printf("%lld\n",ask(shu2)); } } return 0; }