【2019/03/02测试T3】层流

【题目】

传送门

题目描述:

对于一个全集 U U ,对于他的两个子集 A , B A,B ,如果 A B A\subset B B A B⊂A A B = A∩B=\varnothing ,则这两个集合就是 U U 的层流集。

现在小 Z 想把这个问题搬到树上来。他给出 n n 个顶点的无根树,然后他把两个顶点 < u , v > <u,v> 的简单路径所有的顶点加入一个集合,这样就会得到若干个集合。显然所有顶点构成的集合就是全集 U U 。他想知道他随手写出的若干组 < u , v > <u,v> 构成的若干子集是否满足任意两个集合是 U U 的层流集。

输入格式:

第一行是两个整数 n , m n,m 表示有 n n 个顶点, m m 组子集。

接下来是 n 1 n-1 行,每行 2 2 个整数 u , v u,v ,表示 u u ~ v v 有一条边(保证是一颗树)。

接下来 m m 行,每行两个整数 u , v u,v 表示由 u u v v 的简单路径上顶点构成一个子集。

输出格式:

如果给出的 m m 个子集任意两个子集满足是全集的层流集输出 “Yes” 否则输出 “No”

样例数据:

输入
4 2
1 2
2 3
2 4
1 2
4 2

输出
No

提示:

子任务一( 5 5 分): n , m 15 n,m\le15
子任务二( 25 25 分): n , m 1000 n,m\le1000
子任务三( 70 70 分): n , m 100000 n,m\le100000


【分析】

先考虑怎么判断两个集合 A , B A,B 是否是 U U 的层流集。

如果存在两个集合 A , B A,B ,使得 A , B A,B 有交叉(此处的交叉定义为 A , B A,B 有交集但是不存在包含关系),那就不满足任意两个集合都是 U U 的层流集(也就是输出 “No”),如果不存在这样的一对集合,就输出 “Yes”

我们将路径的长度从大到小排序,然后从大到小加边,每次判断之前的边与这条边是否有交叉。

怎么判断是否有交叉呢,不妨在每次加入一条边之后,对这条边上的点染上一个新颜色。判断交叉的时候,就看这条边上有几种颜色,如果有多于 1 1 种的颜色,就说明这条边与之前的边有交叉。

然后怎么判断是否只有 1 1 种颜色呢,可以记录下路径上的最大最小值,判断最大最小值是否相等即可。

可以自己画一下图来理解。

然后具体的实现可以看代码(虽然代码量巨大)。


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int n,m,t,tot;
struct edge{int u,v,len;}e[N];
int first[N],v[N<<1],nxt[N<<1];
int Max[N<<2],Min[N<<2],cov[N<<2];
int fa[N],son[N],dep[N],Size[N],pos[N],top[N];
bool operator<(const edge &p,const edge &q){return p.len>q.len;}
void add(int x,int y)
{
	nxt[++t]=first[x];
	first[x]=t,v[t]=y;
}
void dfs1(int x)
{
	int i,k;
	Size[x]=1;
	for(i=first[x];i;i=nxt[i])
	{
		k=v[i];
		if(k==fa[x])  continue;
		fa[k]=x,dep[k]=dep[x]+1;
		dfs1(k),Size[x]+=Size[k];
		if(Size[son[x]]<Size[k])  son[x]=k;
	}
}
void dfs2(int x,int tp)
{
	top[x]=tp,pos[x]=++tot;
	if(son[x])  dfs2(son[x],tp);
	for(int i=first[x];i;i=nxt[i])
	  if(v[i]!=son[x]&&v[i]!=fa[x])
	    dfs2(v[i],v[i]);
}
int LCA(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])  swap(x,y);
		x=fa[top[x]];
	}
	return (dep[x]<dep[y])?x:y;
}
void pushup(int root)
{
	Min[root]=min(Min[root<<1],Min[root<<1|1]);
	Max[root]=max(Max[root<<1],Max[root<<1|1]);
}
void pushnow(int root,int k)
{
	cov[root]=Min[root]=Max[root]=k;
}
void pushdown(int root,int l,int r,int mid)
{
	if(!cov[root])  return;
	pushnow(root<<1,cov[root]);
	pushnow(root<<1|1,cov[root]);
	cov[root]=0;
}
int queryMax(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)  return Max[root];
	int mid=(l+r)>>1;pushdown(root,l,r,mid);
	if(y<=mid)  return queryMax(root<<1,l,mid,x,y);
	if(x>mid)  return queryMax(root<<1|1,mid+1,r,x,y);
	return max(queryMax(root<<1,l,mid,x,y),queryMax(root<<1|1,mid+1,r,x,y));
}
int FindMax(int x,int y)
{
	int ans=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])  swap(x,y);
		ans=max(ans,queryMax(1,1,n,pos[top[x]],pos[x]));
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])  swap(x,y);
	ans=max(ans,queryMax(1,1,n,pos[x],pos[y]));
	return ans;
}
int queryMin(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)  return Min[root];
	int mid=(l+r)>>1;pushdown(root,l,r,mid);
	if(y<=mid)  return queryMin(root<<1,l,mid,x,y);
	if(x>mid)  return queryMin(root<<1|1,mid+1,r,x,y);
	return min(queryMin(root<<1,l,mid,x,y),queryMin(root<<1|1,mid+1,r,x,y));
}
int FindMin(int x,int y)
{
	int ans=N;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])  swap(x,y);
		ans=min(ans,queryMin(1,1,n,pos[top[x]],pos[x]));
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])  swap(x,y);
	ans=min(ans,queryMin(1,1,n,pos[x],pos[y]));
	return ans;
}
void Cover(int root,int l,int r,int x,int y,int k)
{
	if(l>=x&&r<=y)
	{
		pushnow(root,k);
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)  Cover(root<<1,l,mid,x,y,k);
	if(y>mid)  Cover(root<<1|1,mid+1,r,x,y,k);
	pushup(root);
}
void Modify(int x,int y,int k)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])  swap(x,y);
		Cover(1,1,n,pos[top[x]],pos[x],k);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])  swap(x,y);
	Cover(1,1,n,pos[x],pos[y],k);
}
int main()
{
	int x,y,i,lca;
	scanf("%d%d",&n,&m);
	for(i=1;i<n;++i)
	{
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	dfs1(1),dfs2(1,1);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d",&e[i].u,&e[i].v);
		lca=LCA(e[i].u,e[i].v);
		e[i].len=dep[e[i].u]+dep[e[i].v]-2*dep[lca];
	}
	sort(e+1,e+m+1);
	for(i=1;i<=m;++i)
	{
		int maxn=FindMax(e[i].u,e[i].v);
		int minn=FindMin(e[i].u,e[i].v);
		if(maxn!=minn){puts("No");return 0;}
		Modify(e[i].u,e[i].v,i);
	}
	puts("Yes");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/88077259
T3