题意:一棵树有n个节点,但是除了根节点1外,其他节点都的出度和入度加起来就只有2(就是棵树是由几条链的第一个节点粘在一起的),现在有两种操作(1)"0 v x d",在距离v节点距离d以内的所有节点的权值都加上1,(2)"1 v",查询节点v上的权值。
思路:动态地开n个树状数组,然后每次记录这条枝上的更新,用vc[0]树状数组记录所有会更新到其他枝上的更新。
AC代码如下:
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
vector<int> qu[100010];
vector<int>vc[100010];
map<int,ll> match;
ll MOD=1e6;
int num,vis[100010],L[100010],maxn,ans0;
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int pos,int val)
{
//printf("update %d %d %d\n",x,pos,val);
for(;x<=L[pos];x+=lowbit(x))
vc[pos][x]+=val;
}
int query(int x,int pos)
{
int ans=0;
for(;x>0;x-=lowbit(x))
ans+=vc[pos][x];
return ans;
}
void dfs(int u,int d,int l)
{
vc[d].push_back(0);
vis[u]=1;
match[u]=d*MOD+l;
//printf(" ss %I64d\n",match[u]);
if(qu[u].size()==1)
return;
for(int i=0;i<=1;i++)
if(vis[qu[u][i]]==0)
dfs(qu[u][i],d,l+1);
}
int main()
{
int n,m,i,j,k,u,v,pos,l,len,val,l_1,r_1;
scanf("%d%d",&n,&m);
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
qu[u].push_back(v);
qu[v].push_back(u);
}
num=qu[1].size();
//printf("num %d\n",num);
vis[1]=1;
for(i=1;i<=num;i++)
{
vc[i].push_back(0);
dfs(qu[1][i-1],i,1);
}
maxn=0;
for(i=1;i<=num;i++)
{
L[i]=vc[i].size()-1;
maxn=max(maxn,L[i]);
}
//printf("maxn %d\n",maxn);
L[0]=maxn;
for(i=0;i<=maxn;i++)
vc[0].push_back(0);
while(m--)
{
scanf("%d",&k);
if(k==1)
{
scanf("%d",&u);
pos=match[u]/MOD;
l=match[u]%MOD;
//printf(" %d %d\n",pos,l);
if(l==0)
printf("%d\n",ans0);
else
printf("%d\n",query(l,pos)+query(l,0));
}
else
{
scanf("%d%d%d",&u,&val,&len);
if(u==1)
{
ans0+=val;
update(1,0,val);
update(min(len,maxn)+1,0,-val);
continue;
}
pos=match[u]/MOD;
l=match[u]%MOD;
r_1=min(l+len,L[pos]);
l_1=max(l-len,1);
update(l_1,pos,val);
update(r_1+1,pos,-val);
if(l-len<=0)
ans0+=val;
if(l-len<0)
{
update(1,0,val);
update(len-l+1,0,-val);
update(1,pos,-val);
update(len-l+1,pos,val);
}
}
}
}