题目
给出一颗树,(m)次询问树上不相同的三个点(A,B,C)。我们称一个点(x)被(A)占领当且仅当(dist(A,x)>dist(B,x),dist(A,x)>dist(C,x))。
问(A,B,C)这三个点分别占领了多少个点。
(n,mle 10^5)。
分析
如果是两个点的话,我们找到他们的中点,讨论一下即可。现在有三个点,那么我们对(A),分别算一下与(B)和(C)的dfn序区间,用线段树做一下区间求交即可。也可以扫描线求交,不过最多就四个区间。
代码
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=1e5+1;
const int maxj=17;
int f[maxn][maxj],dep[maxn],dfx,first[maxn],second[maxn],n;
struct TREE {
vector<int> g[maxn];
inline void clear(int n) {
memset(f,0,sizeof f),memset(dep,0,sizeof dep);
memset(first,0,sizeof first),memset(second,0,sizeof second);
for (int i=1;i<=n;++i) g[i].clear();
dfx=0;
}
inline void add(int x,int y) {g[x].push_back(y);}
void dfs(int x,int fa) {
f[x][0]=fa;
dep[x]=dep[fa]+1;
first[x]=++dfx;
for (int v:g[x]) if (v!=fa) dfs(v,x);
second[x]=dfx;
}
void run() {
dfs(1,1);
for (int j=1;j<maxj;++j) for (int i=1;i<=n;++i) f[i][j]=f[f[i][j-1]][j-1];
}
int lca(int x,int y) {
if (dep[x]<dep[y]) swap(x,y);
for (int j=maxj-1;j>=0;--j) if (dep[f[x][j]]>=dep[y]) x=f[x][j];
if (x==y) return x;
for (int j=maxj-1;j>=0;--j) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
return f[x][0];
}
int jump(int x,int y) {
for (int j=maxj-1;j>=0;--j) if ((y>>j)&1) x=f[x][j];
return x;
}
} tree;
struct SGT {
struct node {
int zero,one,two,tag;
int tic;
} t[maxn<<2];
int tim;
SGT ():tim(0) {}
void flow() {++tim;}
void doit(int x) {
t[x].two=t[x].one,t[x].one=t[x].zero,t[x].zero=0;
++t[x].tag;
}
void pushdown(int x,int L,int mid,int R) {
newnode(x<<1,L,mid),newnode(x<<1|1,mid+1,R);
for (int &tmp=t[x].tag;tmp;--tmp) doit(x<<1),doit(x<<1|1);
}
void update(int x,int L,int mid,int R) {
newnode(x<<1,L,mid),newnode(x<<1|1,mid+1,R);
t[x].zero=t[x<<1].zero+t[x<<1|1].zero;
t[x].one=t[x<<1].one+t[x<<1|1].one;
t[x].two=t[x<<1].two+t[x<<1|1].two;
}
void newnode(int x,int L,int R) {
if (t[x].tic!=tim) t[x].tic=tim,t[x].one=t[x].two=0,t[x].zero=R-L+1,t[x].tag=0;
}
void inc(int x,int L,int R,int l,int r) {
newnode(x,L,R);
if (L==l && R==r) {
doit(x);
return;
}
int mid=(L+R)>>1;
pushdown(x,L,mid,R);
if (r<=mid) inc(x<<1,L,mid,l,r); else
if (l>mid) inc(x<<1|1,mid+1,R,l,r); else
inc(x<<1,L,mid,l,mid),inc(x<<1|1,mid+1,R,mid+1,r);
update(x,L,mid,R);
}
void inc(int l,int r) {
if (l>r) return;
inc(1,1,n,l,r);
}
int query() {
return t[1].two;
}
} sgt;
void deal(int a,int b) {
int l=tree.lca(a,b);
if (a==l) {
int d=dep[b]-dep[a];
int jp=d>>1;
int p=tree.jump(b,jp);
sgt.inc(1,first[p]-1);
sgt.inc(second[p]+1,n);
} else if (b==l) {
int d=dep[a]-dep[b];
int jp=(d-1)>>1;
int p=tree.jump(a,jp);
sgt.inc(first[p],second[p]);
} else {
int ad=dep[a]-dep[l],bd=dep[b]-dep[l];
if (ad==bd) {
int p=tree.jump(a,ad-1);
sgt.inc(first[p],second[p]);
} else if (ad>bd) {
int d=ad+bd,jp=(d-1)>>1;
int p=tree.jump(a,jp);
sgt.inc(first[p],second[p]);
} else if (ad<bd) {
int d=ad+bd,jp=d>>1;
int p=tree.jump(b,jp);
sgt.inc(1,first[p]-1);
sgt.inc(second[p]+1,n);
}
}
}
int Ans(int a,int b,int c) {
sgt.flow();
deal(a,b);
deal(a,c);
return sgt.query();
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
int T=read();
while (T--) {
n=read();
tree.clear(n);
for (int i=1;i<n;++i) {
int x=read(),y=read();
tree.add(x,y),tree.add(y,x);
}
tree.run();
int q=read();
while (q--) {
int fir=read(),sec=read(),thr=read();
int afir=Ans(fir,sec,thr);
int asec=Ans(sec,fir,thr);
int athr=Ans(thr,fir,sec);
printf("%d %d %d
",afir,asec,athr);
}
}
return 0;
}