[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
",query(x));
                break;
        }
    }
    return 0;
}
View Code
我是咸鱼。转载博客请征得博主同意Orz
原文地址:https://www.cnblogs.com/sdfzhsz/p/9752482.html