BZOJ 3572 【HNOI2014】 世界树

题目链接:世界树

  首先看到\(\sum m_i\le 3\times 10^5\)这个条件,显然这道题就需要用虚树了。

  在我们构建出虚树之后,就可以用两遍\(dfs\)来求出离每个点最近的议事处了。然后,如果一个点和它在虚树上的父亲所属的议事处不同,那么在原树中的两点之间的路径上就会存在一个分界点,倍增出这个分界点算答案即可。注意不能用路径长度来算,需要使用子树大小。

  然后我们还需要考虑那些不在虚树中的点。我们可以令\(f_x\)表示原树上\(x\)子树中和\(x\)属于同一个议事处的点的个数,那么我们可以把初值赋为\(size_x\),然后减去和它不属于同一个议事处的孩子的\(size\)和这条路径上点的个数即可。然后就可以直接用这个东西和上一部分的贡献一起算出答案了。

  想清楚了细节再写的话还是不难写的。

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 300010

using namespace std;
typedef long long llg;

int head[maxn],next[maxn<<1],to[maxn<<1],tt;
int fa[maxn][19],dep[maxn],n,m,le[maxn],siz[maxn];
int d[maxn],ld,S[maxn],top,qu[maxn],nu[maxn],lq;
int fr[maxn],fd[maxn],ans[maxn],ji[maxn];

int getint(){
	int w=0;bool q=0;
	char c=getchar();
	while((c>‘9‘||c<‘0‘)&&c!=‘-‘) c=getchar();
	if(c==‘-‘) c=getchar(),q=1;
	while(c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar();
	return q?-w:w;
}

bool cmp(int x,int y){return le[x]<le[y];}
void link(int x,int y){
	to[++tt]=y;next[tt]=head[x];head[x]=tt;
	to[++tt]=x;next[tt]=head[y];head[y]=tt;
}

void dfs(int u,int ff){
	fa[u][0]=ff; dep[u]=dep[ff]+1; le[u]=++tt; siz[u]=1;
	for(int i=1,now=2;now<dep[u];i++,now<<=1)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u],v;v=to[i],i;i=next[i])
		if(v!=ff) dfs(v,u),siz[u]+=siz[v];
}

int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y); int t=1;
	for(int now=2;now<dep[x];now<<=1) t++;t--;
	for(int i=t;i>=0;i--)
		if(dep[fa[x][i]]>=dep[y])
			x=fa[x][i];
	if(x==y) return x;
	for(int i=t;i>=0;i--)
		if(fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}

bool pd(int a,int b,int c,int d){return (a<b || (a==b && fr[c]<fr[d]));}
int dis(int x,int y){return dep[x]+dep[y]-(dep[lca(x,y)]<<1);}
int jump(int x,int y){
	for(int i=18;i>=0;i--)
		if(dep[fa[x][i]]>dep[y]) x=fa[x][i];
	return x;
}

void solve(int x,int y,int l){
	int x1=fd[x],x2=fd[y]+dep[x]-dep[y],u=x;
	for(int i=18,v,j=1<<18;i>=0;i--,j>>=1){
		v=fa[u][i]; if(dep[v]<=dep[y]) continue;
		if(pd(x1+j,x2-j,x,y)) x1+=j,x2-=j,u=fa[u][i];
	}
	ans[nu[fr[x]]]+=siz[u]-siz[x];
	ans[nu[fr[y]]]+=siz[l]-siz[u];
}

void dfs1(int u,int ff){
	for(int i=head[u],v,x;v=to[i],i;i=next[i])
		if(v!=ff){
			dfs1(v,u);
			if(fr[v] && fd[u]){
				x=dis(u,fr[v]);
				if(pd(x,fd[u],v,u)) fd[u]=x,fr[u]=fr[v];
			}
		}
}

void dfs2(int u,int ff){
	int x; ji[u]=siz[u];
	if(ff && fr[ff]!=fr[u]){
		x=dis(fr[ff],u);
		if(pd(x,fd[u],ff,u)) fd[u]=x,fr[u]=fr[ff];
	}
	for(int i=head[u],v;v=to[i],i;i=next[i])
		if(v!=ff){
			dfs2(v,u); x=jump(v,u);
			if(fr[v]!=fr[u]) ji[u]-=siz[v]+siz[x]-siz[v];
			else ans[nu[fr[u]]]-=ji[v],ji[u]-=siz[v]-ji[v];
		}
	x=jump(u,ff); ans[nu[fr[u]]]+=ji[u];
	if(ff && fr[u]!=fr[ff] && ff!=fa[u][0]) solve(u,ff,x);
}

int main(){
	File("worldtree");
	n=getint();
	for(int i=2;i<=n;i++) link(getint(),getint());
	tt=0; dfs(1,0); tt=0; m=getint();
	for(int i=1;i<=n;i++) head[i]=0,fd[i]=n+1;
	while(m--){
		lq=getint(); tt=0; d[ld=1]=1;
		for(int i=1;i<=lq;i++){
			nu[qu[i]=getint()]=i;
			fr[qu[i]]=qu[i],fd[qu[i]]=0;
		}
		sort(qu+1,qu+lq+1,cmp); S[top=1]=1;
		for(int i=1,L,x;i<=lq;i++){
			x=qu[i]; L=0;
			while(top){
				L=lca(x,S[top]);
				if(top>1 && dep[S[top-1]]>dep[L]) link(S[top-1],S[top]),top--;
				else if(dep[S[top]]>dep[L]){link(L,S[top--]);break;}
				else break;
			}
			if(S[top]!=L) S[++top]=L,d[++ld]=L;
			if(x!=1) S[++top]=x,d[++ld]=x;
		}
		while(top>1) link(S[top-1],S[top]),top--;
		dfs1(1,0); dfs2(1,0);
		for(int i=1,u;u=d[i],i<=ld;i++) head[u]=fr[u]=0,fd[u]=n+1;
		for(int i=1;i<=lq;i++) printf("%d ",ans[i]);
		for(int i=1;i<=lq;i++) ans[i]=0;
		printf("\n");
	}
	return 0;
}
时间: 2024-10-11 22:34:46

BZOJ 3572 【HNOI2014】 世界树的相关文章

bzoj 3572 [Hnoi2014]世界树(虚树+DP)

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.     世界树的形态可以用一个数学模型来描述:世界树中有n个

BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$(f,x)$,讨论一下边上的点的子树应该靠谁更近 倍增求出分界点 注意有些没出现在虚树上的子树 注意讨论的时候只讨论链上的不包括端点,否则$f$的子树会被贡献多次 学到的一些$trick:$ 1.$pair$的妙用 2.不需要建出虚树只要求虚树的$dfs$序(拓扑序)和$fa$就可以$DP$了 注意

bzoj 3572: [Hnoi2014]世界树

再次跪虚树(DP)(两遍DP挺有意思的..) (这个题的情况,,跪) %%%http://hzwer.com/6804.html 1 #include <bits/stdc++.h> 2 #define LL long long 3 #define N 300005 4 using namespace std; 5 inline int ra() 6 { 7 int x=0,f=1; char ch=getchar(); 8 while (ch<'0' || ch>'9') {if

BZOJ 3572 世界树(虚树)

http://www.lydsy.com/JudgeOnline/problem.php?id=3572 思路:建立虚树,然后可以发现,每条边不是同归属于一端,那就是切开,一半给上面,一半给下面. 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #define N 300005 7 int t

bzoj千题计划255:bzoj3572: [Hnoi2014]世界树

http://www.lydsy.com/JudgeOnline/problem.php?id=3572 明显需要构造虚树 点属于谁管理分三种情况: 1.属于虚树的点 2.在虚树上的边上的点 3.既不属于虚树的点,又不属于虚树上的边的点 第一种情况: 先做一遍树形dp,得到子树中距离它最近的点 再dfs一遍,看看父节点那一块 是否有比它现在的点更近的点 第二种情况: 一条边u-->v 如果u和v属于同一点x管理,那么这条边所代表的所有点也都属于x管理 否则的话,二分一个点tmp,tmp以上的点归

bzoj3572[Hnoi2014]世界树

http://www.lydsy.com/JudgeOnline/problem.php?id=3572 首先我们先构建出虚树 然后在虚树上DP,求出虚树上每个点离最近的临时议事处在哪里 对于虚树上相邻的两个点$u$和$v$,他们连线上一定存在一个分界处,一边一定会去离$u$最近的临时议事处:另一边一定会去离$v$最近的临时议事处 然后就做完了 #include<cstdio> #include<cstdlib> #include<iostream> #include&

BZOJ3572 [Hnoi2014]世界树 【虚树 + 树形dp】

题目 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石. 世界树的形态可以用一个数学模型来描述:世界树中有n个种族,种族的编号分别从1到n,分别生活在编号为1到n的聚居地上,种族的编号与其聚居地的编号相同.有的聚居地之间有双向的道路相连,道路的长度为1.保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环.定义两个聚居地之间的距

[BZOJ 3573][Hnoi2014]米特运输(乱搞)

Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储 存一直是一个大问题.D星上有N个城市,我们将其顺序编号为1到N,1号城市为首都.这N个城市由N-1条单向高速 通道连接起来,构成一棵以1号城市(首部)为根的树,高速通道的方向由树中的儿子指向父亲.树按深度分层: 根结点深度为0,属于第1层:根结点的子节点深度为1,属于第2层:依此类推,深度为i的结点属于第i+l层.建好 高速通道之后,D星人开始考虑如何具体地储存和传输米

bzoj 3575: [Hnoi2014]道路堵塞

Description A 国有N座城市,依次标为1到N.同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数.现在,A国交通部指定了一条从城市1到城市N的路径, 并且保证这条路径的长度是所有从城市1到城市N的路径中最短的.不幸的是,因为从城市1到城市N旅行的人越来越多,这条由交通部指定的路径经常发生堵塞. 现在A国想知道,这条路径中的任意一条道路无法通行时,由城市1到N的最短路径长度是多少. Input 输入文件第一行是三个用空格分开的正整数N.M和L,分别表示城市数目.单向道路数目