傳送門: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;
}