2020牛客多校七 C A National Pandemic

https://ac.nowcoder.com/acm/contest/5672/C
2020牛客多校七 C A National Pandemic_第1张图片
难点就是把操作1的式子变形到最后,w-dep(x)-dep(y)很好维护,2*dep(lca)用树链剖分来维护,好像是比较经典的,把一堆【x到根每个点的权】更新,然后查询y到根的权和,就是y与前面每一个x的lca的深度之和。

#include
using namespace std;
#define maxn (100000+100)
#define ll long long

int n,m,root=1,dfs_clock,op;
vector<int> G[maxn];
int fa[maxn],son[maxn],sz[maxn],deep[maxn],id[maxn],id2[maxn],top[maxn];
ll w[maxn],ver_w[maxn],delta[maxn],sum,c1;
//多组数据则G[],son[],dfs_clock,和线段树维护部分需要初始化
int ql,qr,val;
ll sumv[maxn*4],addv[maxn*4];
ll _sum;

ll build(int o,int l,int r)
{
    int mid=(l+r)/2;
    if(l==r)return sumv[o]=addv[o]=w[l];
    return sumv[o]=(build(o*2,l,mid)+build(o*2+1,mid+1,r));
}

void maintain(int o,int l,int r)
{
    if(l==r)sumv[o]=addv[o];
    else sumv[o]=(sumv[o*2]+sumv[o*2+1]+(ll)addv[o]*(r-l+1));  
}

void query(int o,int l,int r,ll add)
{
    if(ql<=l&&qr>=r)_sum=(_sum+add*(r-l+1)+sumv[o]);
    else
    {
        int mid=(l+r)/2;
        if(ql<=mid)query(o*2,l,mid,(add+addv[o]));
        if(qr>mid)query(o*2+1,mid+1,r,(add+addv[o]));
    }  
}

void update(int o,int l,int r)
{
    if(ql<=l&&qr>=r)addv[o]=(addv[o]+val);
    else
    {
        int mid=(l+r)/2;
        if(ql<=mid)update(o*2,l,mid);
        if(qr>mid)update(o*2+1,mid+1,r);
    }
    maintain(o,l,r);
}

void dfs1(int u,int f)
{
    deep[u]=deep[f]+1;
    sz[u]=1;
    fa[u]=f;
    int maxx=0;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==f)continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[v]>maxx){maxx=sz[v];son[u]=v;}
    }
}

void dfs2(int u,int up)
{
    id[u]=id2[u]=++dfs_clock;
    top[u]=up;
    if(son[u]){dfs2(son[u],up);id2[u]=id2[son[u]];}
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==fa[u] || v==son[u])continue;
        dfs2(v,v);
        id2[u]=id2[v];
    }
}

void Update1(int u,int v,int z)
{
    int tpu=top[u],tpv=top[v];
    while(tpu!=tpv)
    {
        if(deep[tpu]<deep[tpv]){swap(tpu,tpv);swap(u,v);}
        ql=id[tpu],qr=id[u],val=z;
        update(1,1,n);
        u=fa[tpu];
        tpu=top[u];
    }
    if(deep[u]>deep[v])swap(u,v);
    ql=id[u],qr=id[v],val=z;
    update(1,1,n);
}

ll Query1(int u,int v)
{
    _sum=0;
    int tpu=top[u],tpv=top[v];
    while(tpu!=tpv)
    {
        if(deep[tpu]<deep[tpv]){swap(tpu,tpv);swap(u,v);}
        ql=id[tpu],qr=id[u];
        query(1,1,n,0);
        u=fa[tpu];
        tpu=top[u];
    }
    if(deep[u]>deep[v])swap(u,v);
    ql=id[u],qr=id[v];
    query(1,1,n,0);
    return _sum;
}

int main()
{
    //freopen("input.in","r",stdin);
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        int x,y,z;
        for(int i=1;i<=n;i++)w[i]=delta[i]=son[i]=0,G[i].clear();
        dfs_clock=c1=sum=0;
        memset(addv,0,sizeof(addv));
        memset(sumv,0,sizeof(sumv));
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        } 
        dfs1(root,0);
        dfs2(root,root);
        ll num;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&op);
            switch(op)
            {
                case 1:
                    scanf("%d%d",&x,&y);
                    c1++;
                    sum+=y-deep[x];
                    Update1(x,1,2);
                    break;
                case 2:
                    scanf("%d",&x);
                    num=delta[x]+sum-deep[x]*c1+Query1(x,1);
                    if(num>0)delta[x]+= -num;
                    break;
                case 3:
                    scanf("%d",&x);
                    printf("%lld\n",delta[x]+sum-deep[x]*c1+Query1(x,1));
                    break;
            }
        }
    }   
    return 0;
}

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