• [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
  • 相关阅读:
    C# tcp发送十六进制数据
    WPF中通过AForge实现USB摄像头拍照
    借鉴过的别人的帖子之C#篇
    C# 连续的语音识别
    C# NAudio 录音
    AS3 水波纹
    ARM多核心集群服务器
    RK3399Pro Android Rock-X 人工智能开发系列(2)
    智能化连锁门店解决方案
    RK3399Pro Android Rock-X 人工智能开发系列(1)
  • 原文地址:https://www.cnblogs.com/sdfzhsz/p/9752482.html
Copyright © 2020-2023  润新知