洛谷P3676--小清新数据结构题

题目

今天做了一天的LINK-CUT-TREE,非常难受

晚上就只好做点小清新数据结构玩

其实晚上看了半天没看懂,机房dalao随手讲了一下我便恍然大悟

这道题就是一道很裸很裸的链剖,甚至比正常的模版还要水

但是公式十分难推

考虑换根的时候,原来的根(默认为1)到这个根路径以外的点的贡献是不变的

那么对于路径上的点的贡献,洛谷题解的第三篇就讲的很清楚了

所以就贴代码了

// luogu-judger-enable-o2
#include
using namespace std;
struct node
{
    node *ls,*rs;
    long long sum;
    int tag;
}pool[3200005],*tail=pool,*root;
long long sum[200005],ans;
int to[400005],nxt[400005],head[200005];
int size[200005],point[200005],que[200005],dfs_num;
int father[200005],depth[200005],shu1,shu2,shu3;
int n,q,tot,son[200005],top[200005],in[200005],real_sum;
void add(int x,int y)
{
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
void pushdown(node *nd,int l,int r)
{
    if(nd->tag)
    {
        int mid=(l+r)>>1;
        nd->ls->tag+=nd->tag;
        nd->rs->tag+=nd->tag;
        nd->ls->sum+=1ll*(mid-l+1)*nd->tag;
        nd->rs->sum+=1ll*(r-mid)*nd->tag;
        nd->tag=0;
    }
}
void update(node *nd)
{
    nd->sum=nd->ls->sum+nd->rs->sum;
}
void dfs1(int x,int fa)
{
    size[x]=1;
    sum[x]=point[x];
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa) continue;
        depth[y]=depth[x]+1;
        dfs1(y,x);
        sum[x]+=sum[y];
        size[x]+=size[y];
        father[y]=x;
        if(size[y]>size[son[x]]) son[x]=y;
    }
    ans+=1ll*sum[x]*sum[x];
}
void dfs2(int x,int fa,int wow)
{
    top[x]=wow;
    que[++dfs_num]=x;
    in[x]=dfs_num;
    if(son[x]) dfs2(son[x],x,wow);
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa||y==son[x]) continue;
        dfs2(y,x,y);
    }
}
void build(node *&nd,int l,int r)
{
    nd=tail++;
    if(l==r)
    {
        nd->sum=sum[que[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(nd->ls,l,mid);
    build(nd->rs,mid+1,r);
    update(nd);
}
void modify(node *&nd,int l,int r,int L,int R,int delta)
{
    if(l>=L&&r<=R)
    {
        nd->sum+=(r-l+1)*delta;
        nd->tag+=delta;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(nd,l,r);
    if(mid>=L) modify(nd->ls,l,mid,L,R,delta);
    if(midrs,mid+1,r,L,R,delta);
    update(nd);
}
long long query(node *nd,int l,int r,int L,int R)
{
    if(l>=L&&r<=R)
    {
        return nd->sum;
    }
    int mid=(l+r)>>1;
    pushdown(nd,l,r);
    long long ans=0;
    if(mid>=L) ans+=query(nd->ls,l,mid,L,R);
    if(midrs,mid+1,r,L,R);
    return ans;
}
void modify(int x,int y)
{
    int len=0;
    long long now=0;
    while(x)
    {
        now+=query(root,1,n,in[top[x]],in[x]);
        modify(root,1,n,in[top[x]],in[x],y);
        len+=depth[x]-depth[top[x]]+1;
        x=father[top[x]];
    }
    ans+=1ll*len*y*y+2*y*now;
}
long long ask(int x)
{
    long long now=0;
    int len=0;
    while(x)
    {
        now+=query(root,1,n,in[top[x]],in[x]);
        len+=depth[x]-depth[top[x]]+1;
        x=father[top[x]];
    }
    return ans+1ll*(len-1)*real_sum*real_sum-1ll*real_sum*2*(now-real_sum);
}
int main()
{
    cin>>n>>q;
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d",&shu1,&shu2);
        add(shu1,shu2);
        add(shu2,shu1);
    }
    for(int i=1;i<=n;i++)
    scanf("%d",&point[i]);
    dfs1(1,1);
    dfs2(1,1,1);
    build(root,1,n);
    real_sum=sum[1];
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&shu1);
        if(shu1==1)
        {
            scanf("%d%d",&shu2,&shu3);
            modify(shu2,shu3-point[shu2]);
            real_sum+=shu3-point[shu2];
            point[shu2]=shu3;
        }
        else 
        {
            scanf("%d",&shu2);
            printf("%lld\n",ask(shu2));
        }
    }
    return 0;
}

 

你可能感兴趣的:(树链剖分)