给一个节点数为n的树,m个操作,每个操作包涵两个数a,b,第i次操作时,向节点a及其子树,节点b及其子树的数据序列中添加i。m次操作完成后,对于每个节点,查询这棵树上有多少个节点与当前节点至少包涵一个相同数。
首先对子树操作的话,先对树做dfs并编号,这样某节点的子树节点的编号一定是一个连续的区间,并记录一下每个节点子树节点编号的范围,这样操作就是一个线段树的区间更新了。
对于操作,可以开个数组或者向量,que[i],保存下所有与i同时操作的节点,这样在查询节点i的时候,先执行que[i]所有的操作,求一下此时有多少个节点被覆盖就行了。查询的时候依然是按dfs序查询,并且一个节点查询结束后要恢复数据。
另外,还有一个坑,数据给的时候并没有保证边a,b一定是a指向b..只保证了1一定是根...所以还是要存成无向图,然后从1开始dfs...
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <queue>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r
using namespace std;
typedef long long ll;
const int maxn=300000+100;
int x,y;
struct link_edge
{
int v,next;
}edge[maxn];
int en;
int g[maxn];
int ct[maxn];
struct node
{
int id,pre;
int l,r;
int data;
}tree[maxn];
vector<int>que[maxn];
int n,m,p,q;
int id;
int ans[maxn];
struct segmenttree
{
int add[maxn<<2];
int dt[maxn<<2];
void init()
{
memset(dt,0,sizeof dt);
memset(add,0,sizeof add);
}
void pushup(int id,int m)
{
if (add[id])
{
dt[id]=m;
return;
}
else if (m==1) dt[id]=0;
else dt[id]=dt[id<<1]+dt[id<<1|1];
}
void modify(int L,int R,int id,int l,int r,int c)
{
if (L==l && R==r)
{
add[id]+=c;
pushup(id,r-l+1);
return;
}
int m=(l+r)>>1;
if (R<=m) modify(L,R,lson,c);
else if (L>m) modify(L,R,rson,c);
else {
modify(L,m,lson,c); modify(m+1,R,rson,c);
}
pushup(id,r-l+1);
}
}sgt;
void dfs(int i,int pre)
{
tree[i].id=id;
for (int j=g[i]; j!=-1; j=edge[j].next)
{
if (edge[j].v==pre) continue;
id++;
dfs(edge[j].v,i);
}
}
void dfs_find(int i,int &minn,int &maxx,int pre)
{
int k;
minn=tree[i].id;
maxx=tree[i].id;
for (int j=g[i]; j!=-1; j=edge[j].next)
{
k=edge[j].v;
if (k==pre) continue;
dfs_find(k,tree[k].l,tree[k].r,i);
// minn=min(minn,min(tree[k].l,tree[k].id));
maxx=max(maxx,tree[k].r);
}
if (minn==999999999) minn=tree[i].id;
}
void work(int u,int pre)
{
for (int i=0; i<que[u].size(); i++)
{
int v=que[u][i];
sgt.modify(tree[v].l,tree[v].r,1,1,n,1);
}
ans[u]+=sgt.dt[1];
if (ans[u]) ans[u]--;
for (int j=g[u]; j!=-1; j=edge[j].next)
{
if (edge[j].v==pre) continue;
work(edge[j].v,u);
}
for (int i=0; i<que[u].size(); i++)
{
int v=que[u][i];
sgt.modify(tree[v].l,tree[v].r,1,1,n,-1);
}
}
int main()
{
// freopen("in.txt","r",stdin);
memset(g,-1,sizeof g);
memset(ans,0,sizeof ans);
en=0;
scanf("%d%d",&n,&m);
for (int i=1; i<n; i++)
{
scanf("%d%d",&x,&y);
edge[en].v=y;
edge[en].next=g[x];
g[x]=en;
en++;
edge[en].v=x;
edge[en].next=g[y];
g[y]=en;
en++;
}
tree[1].id=1;
id=1;
dfs(1,-1);
dfs_find(1,tree[1].l,tree[1].r,-1);
// for (int i=1; i<=n; i++)
// cout<<tree[i].id<<" "<<tree[i].l<<" "<<tree[i].r<<endl;
sgt.init();
for (int i=1; i<=m; i++)
{
scanf("%d%d",&x,&y);
que[x].push_back(x);
que[x].push_back(y);
que[y].push_back(x);
que[y].push_back(y);
}
work(1,-1);
for(int i=1; i<=n; i++) cout<<ans[i]<<" ";
cout<<endl;
return 0;
}