题意
链接:https://nanti.jisuanke.com/t/A1998
给出一个有根树(根是1),有n个结点。初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L(根节点深度为0)的点的值全部增加X。操作2.查询以x为根的子树的结点值得和。其中N,Q<=1e5。
思路
因为这题是对某一深度的所有点加x,所以不是树链剖分。
我们可以先预处理一下dfs序,顺带把d[u]:u的深度、dd[x]:深度为x的点集求出来。
考虑分块,对某一深度分两种情况:1.这一深度的点的个数<=block;2.这一深度的点的个数>block。
对于情况1:更新操作我们可以暴力,因为block我是取的sqrt(n),那么更新的复杂度最坏也是O(qlog(n)sqrt(n)),还能接受,毕竟数据不是特别强。
对于情况2:我们直接将这一层加上x,即add[deep]+=x。
对于查询操作,我们先线段树计算一下这个点为根的子树的值,当然,线段树只暴力更新了size<=block的层,所以查询也只会查询这些层上的值。我们还要计算一下size>block的层,怎么计算呢?
我们先定义一个map
代码
#include
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define int ll
const int N=200005;
const double eps=1e-8;
const double PI = acos(-1.0);
struct node
{
int to,next;
} eg[N];
int head[N],tot=0,sum[N<<2],add[N];
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void addedge(int u,int v)
{
eg[tot].to=v;
eg[tot].next=head[u];
head[u]=tot++;
}
int in[N],out[N],id=0,q[N],d[N],block,f[N];
vector dd[N];
map M[N];
void dfs(int x,int fa,int deep)
{
q[++id]=x;
in[x]=id;
d[x]=deep;
f[x]=fa;
dd[deep].push_back(x);
for(int i=head[x]; ~i; i=eg[i].next)
{
if(eg[i].to!=fa)
{
dfs(eg[i].to,x,deep+1);
}
}
out[x]=id;
}
void pushUp(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=0;
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushUp(rt);
}
void update(int L,int c,int l,int r,int rt)
{
if(l==r)
{
sum[rt]+=c;
return ;
}
int m=(l+r)>>1;
if(m>=L) update(L,c,l,m,rt<<1);
else update(L,c,m+1,r,rt<<1|1);
pushUp(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
return sum[rt];
}
int m=(l+r)>>1;
int ans=0;
if(m>=L)
ans+=query(L,R,l,m,rt<<1);
if(m::iterator it=M[rt].begin();
ll res=0;
for(;it!=M[rt].end();it++)
{
res+=(it->second)*add[it->first];
}
return res;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n,q;
while(cin>>n>>q)
{
id=0;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
init();
for(int i=0; i>a>>b;
addedge(a,b);
addedge(b,a);
}
block=sqrt(n);
dfs(1,0,0);
build(1,n,1);
for(int i=1; i<=n; i++)
{
if(dd[d[i]].size()>block)
{
int u=i;
while(u)
{
if(!M[u][d[i]])
M[u][d[i]]=1;
else
M[u][d[i]]++;
u=f[u];
}
}
}
// for(int i=1;i<=n;i++)
// cout<>o>>a;
if(o==1)
{
cin>>b;
if(dd[a].size()>block)
{
add[a]+=b;
}
else
{
int sz=dd[a].size();
for(int i=0;i