传送门:CDOJ1590



题目大意:


给你一颗n个节点的树,根为T,初始时所有节点的值为0,然后给你m次操作,三种操作

1,更新一个子树,节点a的子树节点都加上b

2,更新一条树链,将从u-v的所有节点都加上c

3,查询节点的值


题目思路:


这题更新子树很容易想到dfs序,更新树链很容易想到树链剖分,但是如果我们理解树链剖分

的话就知道树链剖分建立重链的过程就是按照dfs序的过程,所以我们在连接重链哪里用个数组

记录子树结束的时间戳,所以在更新子树的时候就按照dfs的方法更新区间[in[a],out[a]]],树链就是

树链剖分的方法,


AC代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e5+100;

int n,m,T;
int val[maxn];
//邻接表
struct st
{
    int v,nex;
}edge[maxn<<2];

int hed[maxn],e;

void add(int u,int v)
{
    edge[e].v = v,edge[e].nex = hed[u],hed[u] = e++;
}

//树链剖分

int Deep[maxn],Size[maxn],fa[maxn],Son[maxn],top[maxn],in[maxn],out[maxn],rk[maxn];
int tid;

void dfs1(int u,int f,int d)
{
    Deep[u] = d;
    fa[u] = f;
    Size[u] = 1;
    for(int i=hed[u];~i;i=edge[i].nex)
    {
        int v = edge[i].v;
        if(v!=f)
        {
            dfs1(v,u,d+1);
            Size[u]+=Size[v];
            if(Son[u]==-1||Size[v]>Size[Son[u]])
            {
                Son[u] = v;
            }
        }
    }
}


void dfs2(int u,int t)
{
    top[u] = t;
    in[u] = ++tid;  //开始的时间戳
    rk[tid] = u;
    if(Son[u]!=-1)
    {
        dfs2(Son[u],t);
        for(int i=hed[u];~i;i=edge[i].nex)
        {
            int v = edge[i].v;
            if(v!=Son[u]&&v!=fa[u])
                dfs2(v,v);
        }

    }
    out[u] = tid;   //结束的时间戳
}

//线段树
int Tree[maxn<<2],c[maxn<<2];

void Build(int l,int r,int rt)
{
    c[rt] = 0;
    if(l==r)
    {
        Tree[rt] = 0;
        return ;
    }
    int mid = (l+r)>>1;
    Build(l,mid,rt<<1);
    Build(mid+1,r,rt<<1|1);
    Tree[rt] = Tree[rt<<1]=Tree[rt<<1|1];
}

void pushdown(int rt,int m)
{
    if(c[rt])
    {
        c[rt<<1]+=c[rt];
        c[rt<<1|1]+=c[rt];
        Tree[rt<<1]+=(m-m/2)*c[rt];
        Tree[rt<<1|1]+=(m/2)*c[rt];
        c[rt] = 0;
    }

}

void updata(int L,int R,int l,int r,int rt,int v)
{
    if(L<=l&&r<=R)
    {
        c[rt]+=v;
        Tree[rt]+=(r-l+1)*v;

        return ;
    }
    pushdown(rt,r-l+1);
    int mid = (l+r)>>1;
    if(L<=mid)updata(L,R,l,mid,rt<<1,v);
    if(R>mid)updata(L,R,mid+1,r,rt<<1|1,v);
    Tree[rt] = Tree[rt<<1]+Tree[rt<<1|1];
}

int quary(int l,int r,int rt,int pos)
{
   if(l==r)
   {
       return Tree[rt];
   }
   pushdown(rt,r-l+1);
   int mid = (l+r)>>1;
   if(pos<=mid)return quary(l,mid,rt<<1,pos);
   else return quary(mid+1,r,rt<<1|1,pos);
}



//运行


void change(int x,int y,int v)
{
    while(top[x]!=top[y])
    {
        if(Deep[top[x]]<Deep[top[y]])swap(x,y);
        updata(in[top[x]],in[x],1,n,1,v);
        x = fa[top[x]];
    }
    if(Deep[x]>Deep[y])swap(x,y);
    updata(in[x],in[y],1,n,1,v);

}

void init()
{
    tid = e = 0;
    memset(hed,-1,sizeof(hed));
    memset(Son,-1,sizeof(Son));
}

int main()
{
    init();
    cin>>n>>m>>T;
    for(int i=1;i<n;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs1(T,T,1);
    dfs2(T,T);
    Build(1,n,1);
    while(m--)
    {
        int k;scanf("%d",&k);
        int a,b,c;
        if(k==1)
        {
            scanf("%d%d",&a,&b);
            updata(in[a],out[a],1,n,1,b);
        }
        else if(k==2)
        {
            scanf("%d%d%d",&a,&b,&c);
            change(a,b,c);
        }
        else
        {
            scanf("%d",&a);
            printf("%d\n",quary(1,n,1,in[a]));
        }
    }
    return 0;
}