• 【luoguP3676】 小清新数据结构题 推式子(LCT维护)


    题意:给定一棵树,每次钦定一个点为根,求以这个点为根时每个点子树权和平方之和,有单点修改.

    虽然有修改,但是没有换根操作(等于说每次询问时只换依次根)

    我们初始的时候不妨令 $1$ 为根,并考虑当根为 $x$ 时与根为 $1$ 时的差别.

    我们发现,当根为 $x$ 时,子树权和发生改变的只是 $1$ 到 $x$ 上这条链上的所有点,其余点子树权在换根后不变.

    然后我们将这条链的贡献列出来(换根前与换根后),发现满足 $ans'=ans+(len-1)tot^2-2tot sum_{i=1}^{k}sum_{i}$

    然后后面那个 $sum sum_{i}$ 用树剖/LCT/DFS序维护一下就好了. 

    #include <cstdio> 
    #include <string> 
    #include <cstring>   
    #include <algorithm>    
    #define N 200008 
    #define ll long long    
    #define lson s[x].ch[0] 
    #define rson s[x].ch[1]  
    using namespace std;     
    ll ans;  
    void setIO(string s) 
    {
        freopen((s+".in").c_str(),"r",stdin); 
        // freopen((s+".out").c_str(),"w",stdout); 
    }        
    int edges; 
    int sta[N],hd[N],to[N<<1],nex[N<<1],val[N];    
    void Add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; }  
    struct LCT 
    {  
        int ch[2],rev,f,size;   
        ll tag,sum,v;   
    }s[N];    
    int get(int x) { return s[s[x].f].ch[1]==x; }
    int Isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x;}             
    void pushup(int x) 
    {
        s[x].sum=s[lson].sum+s[rson].sum+s[x].v;  
        s[x].size=s[lson].size+s[rson].size+1;   
    }
    void add(int x,ll v) 
    {
        s[x].v+=v;   
        s[x].sum+=v*1ll*s[x].size;   
        s[x].tag+=v;  
    }
    void rotate(int x) 
    {
        int old=s[x].f,fold=s[old].f,which=get(x);  
        if(!Isr(old)) s[fold].ch[s[fold].ch[1]==old]=x;   
        s[old].ch[which]=s[x].ch[which^1];      
        if(s[old].ch[which]) s[s[old].ch[which]].f=old;  
        s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold;   
        pushup(old),pushup(x);  
    }    
    void pushdown(int x) 
    {
        if(s[x].tag) 
        {
            if(lson) add(lson,s[x].tag); 
            if(rson) add(rson,s[x].tag);  
            s[x].tag=0; 
        }
    }
    void splay(int x)  
    {  
        int u=x,v=0,fa; 
        for(sta[++v]=u;!Isr(u);u=s[u].f) sta[++v]=s[u].f;   
        for(;v;--v) pushdown(sta[v]);  
        for(u=s[u].f;(fa=s[x].f)!=u;rotate(x))   
            if(s[fa].f!=u) 
                rotate(get(fa)==get(x)?fa:x);   
    }
    void Access(int x) 
    {
        for(int y=0;x;y=x,x=s[x].f) 
            splay(x),rson=y,pushup(x);  
    }     
    void dfs(int u,int ff) 
    {
        s[u].f=ff;             
        s[u].v=val[u]; 
        for(int i=hd[u];i;i=nex[i]) 
            if(to[i]!=ff) dfs(to[i],u),s[u].v+=s[to[i]].v;      
        ans+=s[u].v*s[u].v;     
        pushup(u);   
    }
    int main() 
    {
        // setIO("input");  
        ll tot=0ll;  
        int i,j,n,Q,x,y;
        scanf("%d%d",&n,&Q);   
        for(i=1;i<n;++i)  scanf("%d%d",&x,&y),Add(x,y),Add(y,x); 
        for(i=1;i<=n;++i) scanf("%d",&val[i]),tot+=val[i];  
        dfs(1,0);                
        for(i=1;i<=Q;++i) 
        {
            int op; 
            scanf("%d",&op); 
            if(op==1) 
            {
                scanf("%d%d",&x,&y);             
                int d=y-val[x];     
                Access(x),splay(x);
                ans+=2ll*s[x].sum*d+1ll*s[x].size*d*d;    
                add(x,d);     
                tot+=d;   
                val[x]=y;        
    
            }
            else 
            {
                scanf("%d",&x);                          
                Access(x),splay(x);   
                int siz=s[x].size-1;   
                ll sum=s[x].sum-tot;       
                printf("%lld
    ",ans+1ll*siz*tot*tot-2ll*tot*sum);       
            }
        }
        return 0; 
    }
    

      

  • 相关阅读:
    文档注释
    配置环境变量
    Java编译-->运行
    DOS命令(日后补充)
    字符、字符串函数
    输入字符串,逆序输出
    求矩阵最大元素值,以及行号和列号
    Apache和Tomcat的区别
    C# params关键字
    JSP的隐式对象(session)
  • 原文地址:https://www.cnblogs.com/guangheli/p/12122978.html
Copyright © 2020-2023  润新知