【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\n",ans+1ll*siz*tot*tot-2ll*tot*sum);       
        }
    }
    return 0; 
}

  

posted @ 2019-12-31 10:06  EM-LGH  阅读(212)  评论(0编辑  收藏  举报