CF258E 【Little Elephant and Tree】
题目
看到没啥人写水发题解
一开始的想法:
假如每次操作都是一个节点,那么只需要在根节点打上标记,然后一遍
对于节点
很显然的,
那直接取
然后就想,只要把有交集的
那怎么判断有没有交集呢?交集肯定是放在区间上啊,还是看子树,那直接求个
准备开始码的时候,想到:判断一个点
如果没有交集,线段树上当然可以直接加;如果有交集的话,为什么不能直接加呢?既然都有一颗线段树了,为什么还要去维护没有交集的
因为计算完
所以线段树要支持的操作:区间
注意到
细节:
1、如果当前节点
2、每个节点在
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int N=1e6+10;
int tot,cnt;
int fir[N],dfn[N][2],ans[N];
vector<int>opt[N];
struct edge
{
int to;
int nxt;
}e[2*N];
inline void add(int x,int y)
{
e[++tot].to=y; e[tot].nxt=fir[x]; fir[x]=tot;
e[++tot].to=x; e[tot].nxt=fir[y]; fir[y]=tot;
}
struct tree
{
int left,right;
int val,cnt;
}t[8*N];
inline void build(int p,int l,int r)
{
t[p].left=l,t[p].right=r;
if(l==r) return;
int mid=(t[p].left+t[p].right)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
}
inline void pushup(int p)
{
if(t[p].val>0) t[p].cnt=t[p].right-t[p].left+1;
else t[p].cnt=t[p*2].cnt+t[p*2+1].cnt;
}
inline void change(int p,int l,int r,int c)
{
if(l<=t[p].left&&r>=t[p].right)
{
t[p].val+=c;
pushup(p);
return;
}
int mid=(t[p].left+t[p].right)/2;
if(l<=mid) change(p*2,l,r,c);
if(r>mid) change(p*2+1,l,r,c);
pushup(p);
}
inline void dfs1(int p,int fa)
{
dfn[p][0]=++cnt;
for(int i=fir[p];i;i=e[i].nxt)
if(e[i].to!=fa) dfs1(e[i].to,p);
dfn[p][1]=++cnt;
}
inline void dfs2(int p,int fa)
{
if(opt[p].size()) change(1,dfn[p][0],dfn[p][1],1);
for(int i=0;i<opt[p].size();i++)
change(1,dfn[opt[p][i]][0],dfn[opt[p][i]][1],1);
if(t[1].cnt) ans[p]=t[1].cnt/2-1;
for(int i=fir[p];i;i=e[i].nxt)
if(e[i].to!=fa) dfs2(e[i].to,p);
if(opt[p].size()) change(1,dfn[p][0],dfn[p][1],-1);
for(int i=0;i<opt[p].size();i++)
change(1,dfn[opt[p][i]][0],dfn[opt[p][i]][1],-1);
}
int main()
{
int n,m,a,b;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
add(a,b);
}
dfs1(1,0);
build(1,1,2*n);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
opt[a].push_back(b);
opt[b].push_back(a);
}
dfs2(1,0);
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}