列表

详情


NC20106. [HNOI2014]世界树

描述

世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。 
世界树的形态可以用一个数学模型来描述:世界树中有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,表示世界树中种族的个数。
接下来n-l行,每行两个正整数x,y,表示x聚居地与y聚居地之间有一条长度为1的双向道路。
接下来一行为一个正整数q,表示国王询问的年数。
接下来q块,每块两行:
第i块的第一行为1个正整数m[i],表示第i年授权的临时议事处的个数。
第i块的第二行为m[i]个正整数h[l]、h[2]、…、h[m[i]],表示被授权为临时议事处的聚居地编号(保证互不相同)。

输出描述

输出包含q行,第i行为m[i]个整数,该行的第j(j=1,2…,,m[i])个数表示第i年被授权的聚居地h[j]的临时议事处管理的种族个数。

示例1

输入:

10 
2 1 
3 2 
4 3 
5 4 
6 1 
7 3 
8 3 
9 4 
10 1 
5 
2 
6 1   
5 
2 7 3 6 9   
1 
8  
4 
8 7 10 3   
5 
2 9 3 5 8

输出:

1 9
3 1 4 1 1
10
1 1 3 5
4 1 3 1 1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 237ms, 内存消耗: 43052K, 提交时间: 2021-08-16 23:31:23

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+10;
const int inf = 0x3f3f3f3f;
int tot,head[N],n,k,impt[N],h[N],query[N],lg[N],ans[N];

struct Edge
{
  int next,to,from;
}edge[N<<1];

void addedge(int from,int to) 
{
  	edge[++tot].next=head[from];
 	edge[tot].to=to;
 	head[from]=tot;
}

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
} 


namespace VirtualTree{
int fa[N][20],dfn[N],dep[N],cnt,siz[N];
void pre_dfs(int u,int f,int deep){
	fa[u][0]=f,dep[u]=deep,dfn[u]=++cnt,siz[u]=1;
	for(int i=1;i<=lg[deep];++i) fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v==f) continue;
		pre_dfs(v,u,deep+1);
		siz[u]+=siz[v];
	}
}

int getlca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	while(dep[x]>dep[y]) x=fa[x][lg[dep[x]-dep[y]]-1];
	if(x==y) return x;
	for(int i=lg[dep[x]]-1;i>=0;i--) 
	 	if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}

Edge vedge[N];
int vtot,vhead[N];
void vadd(int from,int to) {
  	vedge[++vtot].next=vhead[from];
 	vedge[vtot].to=to;
 	vedge[vtot].from=from;
 	vhead[from]=vtot;
}

bool cmp(int x,int y){return dfn[x]<dfn[y];} 
int sta[N],top;
void build() {
	sort(impt+1,impt+1+k,cmp);
	sta[top=1]=1;  vtot=0,vhead[1]=0;
	for(int i=1;i<=k;++i)
	{
		if(impt[i]==1) continue; 
		int lca=getlca(impt[i],sta[top]);
		if(lca!=sta[top]){
			while(dfn[lca]<dfn[sta[top-1]]) vadd(sta[top-1],sta[top]),--top; 
			if(dfn[lca]>dfn[sta[top-1]]) vhead[lca]=0,vadd(lca,sta[top]),sta[top]=lca;
			else vadd(lca,sta[top--]);
		}
		vhead[impt[i]]=0,sta[++top]=impt[i];
	}
	for(int i=1;i<top;++i) vadd(sta[i],sta[i+1]);             
}

int dp[N],g[N];//dp记录距离关键点最小距离,g记录对应关键点编号 

void cal(int x,int y)
{
	int p=y,q=y;
	for(int i=lg[dep[p]];i>=0;--i) if(dep[fa[p][i]]>dep[x]) p=fa[p][i];
	ans[g[x]]-=siz[p];
	for(int i=lg[dep[q]];i>=0;--i) {
		int len1=dep[y]-dep[fa[q][i]]+dp[y],len2=dep[fa[q][i]]-dep[x]+dp[x];
		if(dep[fa[q][i]]>dep[x]&&(len1<len2||(len1==len2&&g[y]<g[x]))) q=fa[q][i];
	}
	ans[g[y]]+=siz[q]-siz[y],ans[g[x]]+=siz[p]-siz[q];
}

void dfs1(int u){
	dp[u]=inf;
	for(int i=vhead[u];i;i=vedge[i].next){
		int v=vedge[i].to,dis=dep[v]-dep[u];
		dfs1(v); 
		if(dp[v]+dis<dp[u]) dp[u]=dp[v]+dis,g[u]=g[v];
		else if(dp[v]+dis==dp[u]) g[u]=min(g[u],g[v]);
	} 
	if(query[u]) dp[u]=0,g[u]=u,query[u]=0;
}

void dfs2(int u){
	for(int i=vhead[u];i;i=vedge[i].next){
		int v=vedge[i].to,dis=dep[v]-dep[u];
		if(dp[u]+dis<dp[v]) dp[v]=dp[u]+dis,g[v]=g[u];
		else if(dp[u]+dis==dp[v]) g[v]=min(g[v],g[u]);
		cal(u,v);
		dfs2(v);
	}
	ans[g[u]]+=siz[u];
}

void solve()
{
	k=read();
	for(int i=1;i<=k;++i) 
		impt[i]=read(),query[impt[i]]=1,ans[impt[i]]=0,h[i]=impt[i];
	build();
	dfs1(1);
	dfs2(1);
	for(int i=1;i<=k;++i) printf("%d ",ans[h[i]]);
	puts(""); 
}

}


int main()
{
	n=read(); 
	for(int i=1,x,y;i<n;++i){
		x=read(),y=read();
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
		addedge(x,y),addedge(y,x);
	}
	lg[n]=lg[n-1]+(1<<lg[n-1]==n);
	VirtualTree::pre_dfs(1,0,1);
	int q=read();
	while(q--) VirtualTree::solve();
}

C++14(g++5.4) 解法, 执行用时: 556ms, 内存消耗: 45904K, 提交时间: 2019-04-17 07:57:49

#include<bits/stdc++.h>
using namespace std;
#define fr first
#define sc second
#define REP(u) for(int i=hd[u],v=e[i].v;i;i=e[i].n,v=e[i].v)
#define REQ(u) for(int i=Hd[u],v=E[i].v;i;i=E[i].n,v=E[i].v)
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define p pair<int,int>
const int N=1e6+5;
const int INF=1e7;
struct edge{int n,v;}e[N],E[N];
int n,m,T,u,v,ti,top,top2,tot,rt;
int a[N],b[N],df[N],sz[N],d[N],tn[N],up[N];
int f[N][25],zhan[N],Hd[N],hd[N],ans[N],A[N];
p g[N];
void add(int u,int v){e[++top]=(edge){hd[u],v};hd[u]=top;}
void Add(int u,int v){E[++top2]=(edge){Hd[u],v};Hd[u]=top2;}
void dfs0(int u){
    df[u]=++ti;sz[u]=1;
    REP(u)if(v!=f[u][0])
        f[v][0]=u,d[v]=d[u]+1,dfs0(v),sz[u]+=sz[v];
}
void dfs1(int u){
    if(b[u]==1) g[u]=p(0,u);else g[u]=p(INF,0);
    REQ(u) dfs1(v),g[u]=min(g[u],p(g[v].fr+d[v]-d[u],g[v].sc));
}
void dfs2(int u,int D,int x)
{
    if(p(D,x)<g[u]) g[u]=p(D,x);else D=g[u].fr,x=g[u].sc;
    REQ(u) dfs2(v,D+d[v]-d[u],x);
}
void dfs3(int u)
{
    tn[u]=g[u].sc;
    ans[tn[u]]+=sz[u];
    REQ(u){
        int x=v;
        ROF(j,20,0) if(f[x][j] && d[f[x][j]]>d[u]) x=f[x][j];
        ans[tn[u]]-=sz[up[v]=x];dfs3(v);
    }
}
void dfs4(int u)
{
    REQ(u){
        int x=up[v],y=v,H;
        if(tn[u]==tn[v]) ans[tn[u]]+=sz[x]-sz[v];
        else{
            H=d[tn[v]]+d[u]-g[u].fr;
            H=H&1?H+1>>1:(tn[v]<tn[u]?H>>1:(H>>1)+1);
            ROF(j,20,0) if(f[y][j] && d[f[y][j]]>=H) y=f[y][j];
            ans[tn[v]]+=sz[y]-sz[v];
            ans[tn[u]]+=sz[x]-sz[y];
        }dfs4(v);
    }
}
void dfs5(int u){up[u]=tn[u]=0;REQ(u) dfs5(v);Hd[u]=0;}
int lca(int u,int v)
{
    if(d[u]<d[v]) swap(u,v);
    ROF(j,20,0) if(d[f[u][j]]>=d[v] && f[u][j]) u=f[u][j];
    if(u==v) return u;
    ROF(j,20,0) if(f[u][j]!=f[v][j] && f[u][j]) u=f[u][j],v=f[v][j]; 
    return f[u][0];
}
bool cmp(int x,int y){return df[x]<df[y];}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs0(1);
    for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++)
        	f[i][j]=f[f[i][j-1]][j-1];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&a[i]);
            A[i]=a[i];
            b[a[i]]=1;
        }
        sort(a+1,a+m+1,cmp);
        zhan[tot=1]=a[1];
        FOR(i,2,m){
            int x=a[i],y=lca(x,zhan[tot]);
            while(tot>1&&d[y]<=d[zhan[tot-1]])
                Add(zhan[tot],zhan[tot--]);
            if(zhan[tot]!=y)
            {
                Add(y,zhan[tot]);
                zhan[tot]=y;
            }
            zhan[++tot]=x;
        }
        while(tot>1) Add(zhan[tot],zhan[tot--]);
        rt=zhan[1];
        dfs1(rt);
        dfs2(rt,g[rt].fr,g[rt].sc);
        dfs3(rt);
        dfs4(rt);
        ans[tn[rt]]+=sz[1]-sz[rt]; 
        for(int i=1;i<=m;i++)
            printf("%d ",ans[A[i]]);
        puts("");
        dfs5(rt);
        for(int i=1;i<=m;i++)b[a[i]]=ans[a[i]]=0;
        top2=0;
    }
    return 0;
}

上一题