传送门:洛谷-世界树
题意
世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为1。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居地之间的距离为连接他们的道路的长度;
例如,若聚居地a和b之间有道路,b和c之间有道路,因为每条道路长度为1而且又不可能出现环,所以a与c之间的距离为2。出于对公平的考虑,第i年,世界树的国王需要授权m[i]个种族的聚居地为临时议事处。对于某个种族x(x为种族的编号),如果距离该种族最近的临时议事处为y(y为议事处所在聚居地的编号),则种族x将接受y议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则y为其中编号最小的临时议事处)。
现在国王想知道,在q年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。
数据范围
N<=300000, q<=300000,m[1]+m[2]+…+m[q]<=300000
题解
先建一棵树模拟一下,就会发现对于每个点,如果它的子树里都没有议事处,那么肯定归它管,对于它上面的,找到距离恰为和祖先中第一个议事处距离的一半的,判一下标号大小就好了。
那么结合m的提示,我们对于每一次询问建一颗虚树。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,x,y,h[N],tot,Q,m,dfn,flor;
int head[N],to[N<<1],nxt[N<<1],a[N],b[N],c[N],top;
int d[N],ans[N],f[N][20],sz[N],rem[N];
int id[N],bel[N],s[N],mx;
inline int read()
{
char ch=getchar();int x=0,t=1;
while(ch<'0' || ch>'9') {if(ch=='-') t=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*t;
}
inline bool cmp(int x,int y)
{
return id[x]<id[y];
}
inline int lca(int x,int y)
{
if(d[x]>d[y]) swap(x,y);
int t=d[y]-d[x];
for(register int i=0;(1LL<<i)<=t;i++){
if(t&(1LL<<i)) y=f[y][i];
}
for(register int i=flor;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i];y=f[y][i];
}
}
if(x!=y){
return f[x][0];
}else{
return x;
}
}
inline int dis(int x,int y)
{
return (d[x]+d[y]-2*(d[lca(x,y)]));
}
inline void lk(int u,int v)
{
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;
}
inline void dfs(int x,int fa)
{
int e;sz[x]=1;id[x]=++dfn;
for(register int i=1;(1LL<<i)<=d[x];i++){
f[x][i]=f[f[x][i-1]][i-1];
}
for(register int i=head[x];i;i=nxt[i]){
if(to[i]==fa) continue;
e=to[i];d[e]=d[x]+1;
f[e][0]=x;
dfs(e,x);
sz[x]+=sz[e];
}
mx=max(mx,d[x]);
}
inline void df(int x)
{
c[++dfn]=x;rem[x]=sz[x];int e;
for(register int i=head[x];i;i=nxt[i]){
e=to[i];
df(e);
if(!bel[e]) continue;
int t1=dis(bel[e],x),t2=dis(bel[x],x);
if(((t1==t2)&&bel[e]<bel[x])||(t1<t2)||(!bel[x])) bel[x]=bel[e];
}
}
inline void dff(int x)
{
int e;
for(register int i=head[x];i;i=nxt[i]){
e=to[i];
int t1=dis(bel[e],e),t2=dis(bel[x],e);
if(((t1==t2)&&bel[x]<bel[e])||(t2<t1)||!bel[e]) bel[e]=bel[x];
dff(e);
}
}
inline void solve(int a,int b)
{
int ct=b,x=b;
for(register int i=flor;i>=0;i--){
if(d[f[x][i]]>d[a]){
x=f[x][i];
}
}
rem[a]-=sz[x];
if(bel[a]==bel[b]){
ans[bel[a]]+=sz[x]-sz[b];
}else{
int e;
for(register int i=flor;i>=0;i--){
e=f[ct][i];
if(d[e]<=d[a]) continue;
int t1=dis(bel[a],e),t2=dis(bel[b],e);
if(((t1==t2)&&(bel[b]<bel[a]))||(t1>t2)) ct=e;
}
ans[bel[a]]+=(sz[x]-sz[ct]);
ans[bel[b]]+=(sz[ct]-sz[b]);
}
}
int main(){
n=read();
for(register int i=1;i<n;i++){
int u=read(),v=read();
lk(u,v);lk(v,u);
}
dfs(1,0);
flor=(int)(log(mx)/log(2));
if((1LL<<flor)<mx) flor++;
memset(head,0,sizeof(head));
Q=read();
while(Q--){
dfn=0;top=0;tot=0;
m=read();
for(register int i=1;i<=m;i++){
a[i]=read();b[i]=a[i];
bel[a[i]]=a[i];
}
sort(a+1,a+m+1,cmp);
if(bel[1]!=1) s[++top]=1;
for(register int i=1;i<=m;i++){
int t=a[i],p=0;
while(top>0){
p=lca(s[top],t);
if(top>1 && d[p]<d[s[top-1]]){
lk(s[top-1],s[top]);top--;
}else if(d[p]<d[s[top]]){
lk(p,s[top]);top--;break;
}else break;
}
if(s[top]!=p) s[++top]=p;
s[++top]=t;
}
while(top>1){lk(s[top-1],s[top]);top--;}
df(1);dff(1);
for(register int i=1;i<=dfn;i++){
for(register int j=head[c[i]];j;j=nxt[j]){
solve(c[i],to[j]);
}
}
for(register int i=1;i<=dfn;i++)
ans[bel[c[i]]]+=rem[c[i]];
for(register int i=1;i<=m;i++) printf("%d ",ans[b[i]]);
printf("\n");
for(register int i=1;i<=dfn;i++){
ans[c[i]]=bel[c[i]]=rem[c[i]]=head[c[i]]=0;
}
}
return 0;
}
ps:代码参照hzwer