[LUOGU3676]小清新数据结构题
真·清新
如果根是1的话,先预处理出来没有变化的时候的answer,然后修改的时候就相当于1-x的路径上的节点上的贡献就由∑(sumx)^2 变成∑(sumx+detla)^2 这样的话就加了x^2*(路径上点的个数)+2*x*(路径上点权和)
换根的推导式子如下,摘自洛谷题解区。。。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N=200005; int ch[N][2],fa[N],siz[N],to[N<<1],nxt[N<<1],head[N],ecnt,n,m; long long ans,val[N],sqsum[N],a[N],tag[N]; bool rev[N]; #define ls ch[x][0] #define rs ch[x][1] inline void add(int bg,int ed) { nxt[++ecnt]=head[bg]; to[ecnt]=ed; head[bg]=ecnt; } inline bool is_rt(int x) { return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x; } inline bool ck(int x) { return x==ch[fa[x]][1]; } inline void pushup(int x) { siz[x]=siz[ls]+siz[rs]+1; sqsum[x]=sqsum[ls]+sqsum[rs]+val[x]; } inline void rotate(int x) { int f=fa[x],ff=fa[f]; bool tag=ck(x); if(!is_rt(f)) ch[ff][f==ch[ff][1]]=x; ch[f][tag]=ch[x][tag^1]; fa[ch[f][tag]]=f; ch[x][tag^1]=f; fa[f]=x; fa[x]=ff; pushup(f); pushup(x); } inline void pushdown(int x) { if(rev[x]) { rev[ls]^=1; rev[rs]^=1; swap(ls,rs); rev[x]=0; } val[x]+=tag[x]; tag[ls]+=tag[x]; tag[rs]+=tag[x]; sqsum[ls]+=tag[x]*siz[ls]; sqsum[rs]+=tag[x]*siz[rs]; tag[x]=0; } int top,stk[N]; inline void splay(int x) { stk[top=1]=x; for(int i=x; !is_rt(i); i=fa[i]) stk[++top]=fa[i]; for(int i=top;i;i--) pushdown(stk[i]); for(int f; !is_rt(x); rotate(x)) if(!is_rt(f=fa[x])) rotate(ck(x)==ck(f)?f:x); pushup(x); } inline void access(int x) { for(int t=0; x; x=fa[t=x]) splay(x),ch[x][1]=t,pushup(x); } inline void makeroot(int x) { access(x); splay(x); rev[x]=1; } inline void split(int a,int b) { makeroot(a); access(b); splay(b); } inline long long query(int x) { split(x,1); return ans+val[1]*(1ll*(siz[1]+1)*val[1]-(sqsum[1]<<1)); } inline void change(int x,int v) { split(x,1); ans+=v*v*1ll*(siz[1])+(sqsum[1]<<1)*v; tag[1]+=v; sqsum[1]+=v*siz[1]; } void dfs(int x) { for(int i=head[x]; i; i=nxt[i]) { if(fa[x]^to[i]) { fa[to[i]]=x; dfs(to[i]); val[x]+=val[to[i]]; } } ans+=1ll*val[x]*val[x]; } void link(int x,int y) { makeroot(x); fa[x]=y; } int q,tpx[N],tpy[N]; int main() { scanf("%d%d",&n,&q); for(int i=1,x,y; i<n; i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);//,tpx[i]=x,tpy[i]=y; for(int i=1; i<=n; i++) scanf("%lld",&a[i]),val[i]=a[i]; int x,opt; dfs(1);long long y; while(q--) { scanf("%d%d",&opt,&x); switch (opt) { case 1: scanf("%lld",&y); y-=a[x],a[x]+=y,change(x,y); break; case 2: printf("%lld\n",query(x)); break; } } return 0; }
我是咸鱼。转载博客请征得博主同意Orz