3667. 【HNOI2014】世界树(worldtree)
3667. 【HNOI2014】世界树(worldtree)
首先我们对于每次询问建立一个虚树
然后对于虚树上每一个点我们先做一遍dfs预处理出离它最近的可行点和距离;
然后对一个可行点x我们就先ans[x]+=size[x];接着遍历x的儿子假设是y,如果y也是可行点那么就寻找x和y之间的分界点分别给y加上答案,再给x减去属于y的答案。如果y是中间点(建虚树时的LCA但不是可行点)那么就寻找x与离y最近的点的分界点进行同样的操作,记得答案要加给离y最近的点。
如果x是中间点,那么我们就用离x最近的点假设是x'进行上面的操作(具体的自己可以思考一下,细节还挺多的。)
然后就完结了
我的代码又丑又长:阅读需谨慎
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=600001;
struct nup{int id,qz;}a[N];
int n,x,y,m,i,j,k,l,e[N][3],h[N],size[N],dfn[N],in[N],out[N],tot,num,cnt,fz[N][20],z[N],h1[N],e1[N][3],tot1,ans[N],dep[N],bz1[N],b[N],fa[N],V[N][2];
bool cmp(nup x,nup y){return x.qz<y.qz;}
void dfs(int x,int father)
{
size[x]++;in[x]=++num;dfn[num]=x;fz[x][0]=father;dep[x]=dep[father]+1;
for(int i=h[x];i;i=e[i][0])
if(e[i][1]!=father) dfs(e[i][1],x),size[x]+=size[e[i][1]];
out[x]=num;
}
void add(int u,int v)
{
e[++tot][0]=h[u];
e[tot][1]=v;
h[u]=tot;
}
void add1(int u,int v)
{
e1[++tot1][0]=h1[u];
e1[tot1][1]=v;
h1[u]=tot1;
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=19;i>=0;i--) if(dep[fz[x][i]]>=dep[y]) x=fz[x][i];
if(x==y) return x;
for(int i=19;i>=0;i--) if(fz[x][i]!=fz[y][i]) x=fz[x][i],y=fz[y][i];
x=fz[x][0];return x;
}
void build_xs(int num)
{
sort(a+1,a+1+num,cmp);
int top=1;z[top]=1;h1[1]=0;tot1=0;
for(int i=1;i<=num;i++)
if(a[i].id!=1)
{
int lca=LCA(a[i].id,z[top]);
if(lca!=z[top])
{
while(in[z[top-1]]>in[lca])
add1(z[top-1],z[top]),top--;
if(in[lca]!=in[z[top-1]])
h1[lca]=0,add1(lca,z[top]),z[top]=lca;
else add1(lca,z[top]),top--;
}
h1[a[i].id]=0;z[++top]=a[i].id;
}
for(int i=top;i>1;i--)
add1(z[i-1],z[i]);
}
int find(int x,int wz,int y,int wz1,int bh,int bh1)
{
int mid=0;
wz=wz-wz1;
if((dep[y]-wz-dep[x])%2==1)
mid=(dep[y]-wz-dep[x])/2+dep[x];
else
{
if(bh<bh1) mid=dep[x]+(dep[y]-wz-dep[x])/2;
else mid=dep[x]+(dep[y]-wz-dep[x])/2-1;
}
mid++;if(mid<dep[x]) mid=dep[x]+1;
for(int i=19;i>=0;i--) if(dep[fz[y][i]]>=mid) y=fz[y][i];
return y;
}
void dfs2(int x,int father)
{
int num=1e9+7,wz=0;
for(int i=h1[x];i;i=e1[i][0])
if(e1[i][1]!=father)
{
dfs2(e1[i][1],x);
if(bz1[e1[i][1]]==1)
{
if((dep[e1[i][1]]-dep[x])<num) num=(dep[e1[i][1]]-dep[x]),wz=e1[i][1];
else if((dep[e1[i][1]]-dep[x])==num&&wz>e1[i][1]) num=(dep[e1[i][1]]-dep[x]),wz=e1[i][1];
}
else
{
if((V[e1[i][1]][0]+dep[e1[i][1]]-dep[x])<num) num=(V[e1[i][1]][0]+dep[e1[i][1]]-dep[x]),wz=V[e1[i][1]][1];
else if((V[e1[i][1]][0]+dep[e1[i][1]]-dep[x])==num&&wz>V[e1[i][1]][1]) num=(V[e1[i][1]][0]+dep[e1[i][1]]-dep[x]),wz=V[e1[i][1]][1];
}
}
V[x][0]=num;V[x][1]=wz;
}
void dfs1(int x,int father)
{
if(x==493)
l=0;
fa[x]=father;
int num=1e9+7,wz=0;
for(int i=h1[x];i;i=e1[i][0])
if(e1[i][1]!=father) dfs1(e1[i][1],x);
if(bz1[x]==1)
{
ans[x]+=size[x];
for(int i=h1[x];i;i=e1[i][0])
if(e1[i][1]!=father)
{
if(bz1[e1[i][1]]==1)
{
int cnt=find(x,0,e1[i][1],0,x,e1[i][1]);
ans[x]-=size[cnt];
ans[e1[i][1]]+=size[cnt]-size[e1[i][1]];
}
else
{
if((dep[e1[i][1]]-dep[x])>V[e1[i][1]][0]||((dep[e1[i][1]]-dep[x])==V[e1[i][1]][0]&&V[e1[i][1]][1]<x))
{
int cnt=find(x,0,e1[i][1],V[e1[i][1]][0],x,V[e1[i][1]][1]);
ans[x]-=size[cnt];
ans[V[e1[i][1]][1]]+=size[cnt]-size[e1[i][1]];
}
else
{
ans[x]-=size[e1[i][1]];
}
}
}
}
else
{
num=V[x][0],wz=V[x][1];
int ll=x,llr=0;
while(bz1[ll]==0&&fa[ll]!=0)
{
llr+=dep[ll]-dep[fa[ll]];
ll=fa[ll];
if(bz1[ll]==0)
{if((V[ll][0]+llr)<num||((V[ll][0]+llr)==num&&V[ll][1]<wz)) wz=V[ll][1],num=(V[ll][0]+llr);}
else if(llr<num||(llr==num&&wz>ll)) num=llr,wz=ll;
}
ans[wz]+=size[x];
for(int i=h1[x];i;i=e1[i][0])
if(e1[i][1]!=father&&e1[i][1]!=wz&&V[e1[i][1]][1]!=wz)
{
if(bz1[e1[i][1]]==0)
{
int cnt=find(x,num,e1[i][1],V[e1[i][1]][0],wz,V[e1[i][1]][1]);
ans[wz]-=size[cnt];
ans[V[e1[i][1]][1]]+=size[cnt]-size[e1[i][1]];
}
else
{
int cnt=find(x,num,e1[i][1],0,wz,e1[i][1]);
ans[wz]-=size[cnt];
ans[e1[i][1]]+=size[cnt]-size[e1[i][1]];
}
}
else if((e1[i][1]==wz||(V[e1[i][1]][1]==wz))&&wz!=father) ans[wz]-=size[e1[i][1]];
}
}
int main()
{
freopen("worldtree.in","r",stdin);
freopen("worldtree.out","w",stdout);
scanf("%d",&n);
for(i=1;i<n;i++) {scanf("%d%d",&x,&y);add(x,y);add(y,x);}
dfs(1,0);
for(i=1;i<=19;i++)
for(j=1;j<=n;j++)
fz[j][i]=fz[fz[j][i-1]][i-1];
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d",&k);memset(ans,0,sizeof ans);
for(j=1;j<=k;j++) scanf("%d",&a[j].id),a[j].qz=in[a[j].id],bz1[a[j].id]=1,b[j]=a[j].id;//remember to clear the array bz1;
build_xs(k);
dfs2(1,0);
dfs1(1,0);
for(j=1;j<=k;j++) printf("%d ",ans[b[j]]),ans[b[j]]=0,bz1[b[j]]=0;
printf("\n");
}
}

浙公网安备 33010602011771号