【XSY1545】直径 虚树 DP
题目大意
 给你一棵\(n\)个点的树,另外还有\(m\)棵树,第\(i\)棵树与原树的以\(r_i\)为根的子树形态相同。这\(m\)棵树之间也有连边,组成一颗大树。求这棵大树的直径长度。
\(n,m\leq 300000\)
题解
 我们先用DP求出以原树的第\(i\)个点为根的子树的直径,那么以原树的第\(i\)个点为根的子树中的某个点为一个端点的最长路的另一个端点一定在直径的一端。
 然后我们遍历第\(i\)棵树与其他树之间的边,求出每个点走到其他树的最长路。然后用虚树把这些边在第\(i\)棵树的端点和\(r_i\)连在一起,用DP合并。
 zjt大爷:明明可以直接bfs两次为什么要DP?
 时间复杂度:\(O((n+m)\log n)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1200010;
struct list
{
	int v[maxn];
	int t[maxn];
	int h[maxn];
	int n;
	list()
	{
		n=0;
		memset(h,0,sizeof h);
	}
	void add(int x,int y)
	{
		n++;
		v[n]=y;
		t[n]=h[x];
		h[x]=n;
	}
};
struct list2
{
	int x[maxn];
	int y[maxn];
	int x2[maxn];
	int y2[maxn];
	int t[maxn];
	int h[maxn];
	int n;
	list2()
	{
		n=0;
		memset(h,0,sizeof h);
	}
	void add(int a,int a2,int b,int b2)
	{
		n++;
		x[n]=a;
		x2[n]=a2;
		y[n]=b;
		y2[n]=b2;
		t[n]=h[a];
		h[a]=n;
	}
};
int n,m;
namespace tree
{
	list l;
	struct p3
	{
		int d,x,y;
		p3(int a=0,int b=0,int c=0)
		{
			d=a;
			x=b;
			y=c;
		}
	};
	int operator <(p3 a,p3 b)
	{
		return a.d<b.d;
	}
	p3 a[maxn];
	int d[maxn];
	int f[maxn];
	int st[600010][21];
	int g[maxn];
	int g2[maxn];
	int ti;
	int bg[maxn];
	int ed[maxn];
	int w[maxn];
	int o[maxn];
	int dmin(int x,int y)
	{
		return d[x]<d[y]?x:y;
	}
	void init()
	{
		ti=0;
		memset(f,0,sizeof f);
	}
	void dfs(int x,int fa,int dep)
	{
		bg[x]=++ti;
		w[ti]=x;
		d[x]=dep;
		f[x]=fa;
		g[x]=1;
		g2[x]=x;
		a[x]=p3(1,x,x);
		int i;
		for(i=l.h[x];i;i=l.t[i])
			if(l.v[i]!=fa)
			{
				dfs(l.v[i],x,dep+1);
				a[x]=max(a[x],p3(g[x]+g[l.v[i]],g2[x],g2[l.v[i]]));
				a[x]=max(a[x],a[l.v[i]]);
				if(g[l.v[i]]+1>g[x])
				{
					g[x]=g[l.v[i]]+1;
					g2[x]=g2[l.v[i]];
				}
				ti++;
				w[ti]=x;
			}
		ed[x]=ti;
	}
	void buildst()
	{
		int i,j;
		for(i=1;i<=ti;i++)
			st[i][0]=w[i];
		for(j=1;j<=20;j++)
			for(i=1;i+(1<<j)-1<=ti;i++)
				st[i][j]=dmin(st[i][j-1],st[i+(1<<(j-1))][j-1]);
		o[1]=0;
		for(i=2;i<=ti;i++)
			o[i]=o[i/2]+1;
	}
	int getlca(int x,int y)
	{
		x=bg[x];
		y=bg[y];
		if(x>y)
			swap(x,y);
		int t=o[y-x+1];
		return dmin(st[x][t],st[y-(1<<t)+1][t]);
	}
	int getdist(int x,int y)
	{
		int lca=getlca(x,y);
		return d[x]+d[y]-2*d[lca]+1;
	}
}
list2 l2;
int r[maxn];
ll ans;
ll f[maxn];
int stack[maxn];
int top;
int c[maxn];
int par[maxn];
ll g[maxn];
int cnt;
int tag[maxn];
int dfscmp(int x,int y)
{
	return tree::bg[x]<tree::bg[y];
}
int getmaxdist(int x,int y)
{
	return max(tree::getdist(y,tree::a[x].x),tree::getdist(y,tree::a[x].y));
}
void pushup(int x)
{
	int v=par[x];
	if(!v)
		return;
	ans=max(ans,g[v]+g[x]+tree::d[x]-tree::d[v]-1);
	g[v]=max(g[v],g[x]+tree::d[x]-tree::d[v]);
}
void dp(int x,int x2,int fa)
{
	f[x]=getmaxdist(r[x],x2);
	int i;
	for(i=l2.h[x];i;i=l2.t[i])
		if(l2.y[i]!=fa)
			dp(l2.y[i],l2.y2[i],x);
	cnt=0;
	c[++cnt]=x2;
	for(i=l2.h[x];i;i=l2.t[i])
		if(l2.y[i]!=fa)
		{
			c[++cnt]=l2.x2[i];
			ans=max(ans,getmaxdist(r[x],l2.x2[i])+f[l2.y[i]]);
			f[x]=max(f[x],f[l2.y[i]]+tree::getdist(x2,l2.x2[i]));
			if(tag[l2.x2[i]]==x)
			{
				ans=max(ans,g[l2.x2[i]]+f[l2.y[i]]);
				g[l2.x2[i]]=max(g[l2.x2[i]],f[l2.y[i]]+1);
			}
			else
			{
				tag[l2.x2[i]]=x;
				g[l2.x2[i]]=f[l2.y[i]]+1;
			}
		}
	if(tag[x2]!=x)
	{
		tag[x2]=x;
		g[x2]=1;
	}
	sort(c+1,c+cnt+1,dfscmp);
	cnt=unique(c+1,c+cnt+1)-c-1;
	top=0;
	int lca;
	for(i=1;i<=cnt;i++)
	{
		if(!top)
		{
			stack[++top]=c[i];
			par[c[i]]=0;
			continue;
		}
		int lca=tree::getlca(c[i],c[i-1]);
		while(top&&tree::d[stack[top]]>tree::d[lca])
		{
			if(tree::d[stack[top-1]]<tree::d[lca])
			{
				par[lca]=stack[top-1];
				par[stack[top]]=lca;
				g[lca]=1;
			}
			pushup(stack[top]);
			top--;
		}
		if(tree::d[stack[top]]<tree::d[lca])
		{
			par[lca]=stack[top];
			stack[++top]=lca;
		}
		par[c[i]]=stack[top];
		stack[++top]=c[i];
	}
	while(top)
	{
		pushup(stack[top]);
		top--;
	}
}
int main()
{
	memset(tag,0,sizeof tag);
	freopen("diameter.in","r",stdin);
	freopen("diameter.out","w",stdout);
	tree::init();
	scanf("%d%d",&n,&m);
	int i,x,y,x2,y2;
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		tree::l.add(x,y);
		tree::l.add(y,x);
	}
	tree::dfs(1,0,1);
	tree::buildst();
	for(i=1;i<=m;i++)
		scanf("%d",&r[i]);
	for(i=1;i<m;i++)
	{
		scanf("%d%d%d%d",&x,&x2,&y,&y2);
		l2.add(x,x2,y,y2);
		l2.add(y,y2,x,x2);
	}
	ans=0;
	dp(1,r[1],0);
	printf("%lld\n",ans);
	return 0;
}
【XSY1545】直径 虚树 DP的更多相关文章
- bzoj 3572世界树    虚树+dp
		题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ... 
- bzoj 2286 [Sdoi2011]消耗战   虚树+dp
		题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ... 
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
		[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ... 
- [BZOJ5287][HNOI2018]毒瘤(虚树DP)
		暴力枚举非树边取值做DP可得75. 注意到每次枚举出一个容斥状态的时候,都要做大量重复操作. 建立虚树,预处理出虚树上两点间的转移系数.也可动态DP解决. 树上倍增.动态DP.虚树DP似乎是这种问题的 ... 
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
		2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ... 
- BZOJ 3572 [HNOI2014]世界树 (虚树+DP)
		题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ... 
- 洛谷P2495 [SDOI2011]消耗战(虚树dp)
		P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ... 
- bzoj 3611 [Heoi2014]大工程(虚树+DP)
		3611: [Heoi2014]大工程 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 408 Solved: 190[Submit][Status] ... 
- bzoj 3572 [Hnoi2014]世界树(虚树+DP)
		3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 645 Solved: 362[Submit][Status] ... 
随机推荐
- Can’t connect to local MySQL server through socket 原因解析
			在连接mysql的时,经常会出现以下错误提示: ERROR (HY000): Can't connect to local MySQL server through socket '/var/lib/ ... 
- HDU 3478 Catch (连通性&&二分图判断)
			链接 [https://vjudge.net/contest/281085#problem/C] 题意 一个n个点,m条边的图,开始的点是s 每次必须移动到相邻的位置,问你是否存在某个时刻所有点都可能 ... 
- pdf转eps后存在大片空白的处理
			之前pdf转eps的方式是用acrobat直接转,发现每次转完后,图片都显示在一张A4纸上,插入到论文中时会出现大片空白:但在pdf中是没有这么多空白的,与裁剪没关系. 后来在 http://tex. ... 
- debian下 Hadoop 1.0.4 集群配置及运行WordCount
			说明:我用的是压缩包安装,不是安装包 官网安装说明:http://hadoop.apache.org/docs/r1.1.2/cluster_setup.html,繁冗,看的眼花...大部分人应该都不 ... 
- gethostbyname用法
			//会优先查询解析%windir%\system32\drivers\etc\hosts中静态dns表 //一个域名可对应多个IP hostent->h_addr_list ==> 是in ... 
- Html5使用canvas作图线宽很粗
			自己使用canvas画图是碰到的问题,在这里记录一下.我把lineWidth设置为1,但是很粗,而且发虚.代码如下: <script type="text/javascript&quo ... 
- Freemarker 页面静态化技术使用入门案例
			在访问 新闻.活动.商品 详情页面时, 路径可以是 xx[id].html, 服务器端根据请求 id, 动态生成 html 网页,下次访问数据时,无需再查询数据,直接将 html 静态页面返回.这样一 ... 
- 转《在浏览器中使用tensorflow.js进行人脸识别的JavaScript API》
			作者 | Vincent Mühle 编译 | 姗姗 出品 | 人工智能头条(公众号ID:AI_Thinker) [导读]随着深度学习方法的应用,浏览器调用人脸识别技术已经得到了更广泛的应用与提升.在 ... 
- python(Django之组合搜索、JSONP、XSS过滤 )
			一.组合搜索 二.jsonp 三.xss过滤 一.组合搜索 首先,我们在做一个门户网站的时候,前端肯定是要进行搜索的,但是如果搜索的类型比较多的话,怎么做才能一目了然的,这样就引出了组合搜索的这个案例 ... 
- php 将数组转换网址URL参数
			$array =array ( 'id' =123, 'name' = 'dopost' );echo http_build_query( $array );//得到结果id=123name=dopo ... 
