【题目描述】
对于一个全集U,对于他的两个子集A,B,如果 A⊂B或B⊂A或A∩B=∅,则
这两个集合就是U的层流集。
现在Z 想把这个问题搬到树上来。他给出 N个顶点的无根树,然后他把两个
顶点<u,v>的简单路径所有的顶点加入一个集合,这样就会得到若干个集合。显
然所有顶点构成的集合就是全集U。他想知道他随手写出的若干组<u,v>构成的
若干子集是否满足任意两个集合是U的层流集
【输入数据】
第一行是两个整数N,M表示有 N个顶点,M组子集
接下来是N-1行,每行 2个整数U,V,表示U~V有一条边(保证是一颗树)
接下来M行,每行两个整数u,v表示由 u到 v 的简单路径上顶点构成一个子
集
【输出数据】
如果给出的M 个子集任意两个子集满足是全集的层流集输出"Yes"否则输出"No"
【样例输入】
4 2
1 2
2 3
2 4
1 2
4 2
【样例输出】
No
【输入样例 2】
6 5
1 2
2 3
3 4
5 6
5 2
2 1
6 6
1 4
3 4
4 1
【输出样例 2】
Yes
【数据范围】
子任务一:5分,N,M<=15
子任务二:25分,N,M<=1000
子任务三:70分,N,M<=100000
考虑覆盖的情况:大的盖住小的,小的被大的盖住。
那么把边按照长度从大到小排序就只有小的被大的盖住的情况。
给每条边一个颜色。
可以发现如果当前路径上只有一种颜色,那么这条路径是符合要求的。
如果一条路径上有不止一种颜色,说明答案一定是"No"。
排序过后,可以排除------&&&-------###-------这种情况,
就是一个长一点的包住了多个短的。
如果先覆盖短边,统计到长边的时候就会出现它中间有多种颜色的情况。这是不符的。
同SCOI染色。
#include<bits/stdc++.h>
#define lc (root<<1)
#define rc ((root<<1)|1)
#define mid ((l+r)>>1)
using namespace std;
const int maxn=1e5+10;
int n,m,a,b,c,col=1;
int t[maxn],dfn[maxn],tot=0;
int son[maxn],fa[maxn],sz[maxn],dep[maxn],top[maxn];
int cnt=0,Head[maxn],Next[maxn<<1],V[maxn<<1];
struct Node{int u,v,g,len;}e[maxn];
bool operator<(Node a,Node b){return a.len>b.len;}
struct node{int cl,cr,cov,num;node(){cov=cl=cr=0;}}T[maxn<<2];
void add(int u,int v){++cnt,Next[cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
void dfs1(int u,int f){
sz[u]=1,son[u]=0;
for(int i=Head[u];i;i=Next[i]) if(V[i]!=f){
dep[V[i]]=dep[u]+1,fa[V[i]]=u;
dfs1(V[i],u),sz[u]+=sz[V[i]];
if(sz[son[u]]<sz[V[i]]) son[u]=V[i];
}
}
void dfs2(int u,int tp){
t[dfn[u]=++tot]=u,top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=Head[u];i;i=Next[i])
if(V[i]!=fa[u]&&V[i]!=son[u])
dfs2(V[i],V[i]);
}
void pushnow(int root,int val){T[root].cl=T[root].cr=T[root].cov=val,T[root].num=1;}
node pushup(node Tl,node Tr){
node ret;
ret.num=Tl.num+Tr.num-(Tl.cr==Tr.cl);
ret.cl=Tl.cl,ret.cr=Tr.cr;
return ret;
}
void pushdown(int root){
if(T[root].cov){
pushnow(lc,T[root].cov);
pushnow(rc,T[root].cov);
T[root].cov=0;
}
}
void build(int root,int l,int r){
if(l==r){T[root].cl=T[root].cr=1,T[root].cov=0,T[root].num=1;return;}
build(lc,l,mid),build(rc,mid+1,r);
T[root]=pushup(T[lc],T[rc]);
}
int lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}if(dep[u]<dep[v]) swap(u,v);
return v;
}
node query(int root,int l,int r,int x,int y){
if(l>=x&&r<=y) return T[root];
pushdown(root);
if(y<=mid) return query(lc,l,mid,x,y);
if(x>mid) return query(rc,mid+1,r,x,y);
return pushup(query(lc,l,mid,x,y),query(rc,mid+1,r,x,y));
}
void change(int root,int l,int r,int x,int y,int val){
if(l>=x&&r<=y) return pushnow(root,val);
pushdown(root);
if(x<=mid) change(lc,l,mid,x,y,val);
if(y> mid) change(rc,mid+1,r,x,y,val);
T[root]=pushup(T[lc],T[rc]);
}
int ask(int x,int y,int ans=0,int xl=0,int yl=0){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y),swap(xl,yl);
node ret=query(1,1,n,dfn[top[x]],dfn[x]);
ans+=ret.num-(ret.cr==xl);
xl=ret.cl,x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y),swap(xl,yl);
node ret=query(1,1,n,dfn[y],dfn[x]);
ans+=ret.num-((ret.cr==xl)+(ret.cl==yl));
return ans;
}
void modify(int x,int y,int val){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
change(1,1,n,dfn[top[x]],dfn[x],val);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
change(1,1,n,dfn[y],dfn[x],val);
}
int main(){
n=read(),m=read();
for(int i=1;i<n;++i) a=read(),b=read(),add(a,b),add(b,a);
dfs1(1,0),dfs2(1,1),build(1,1,n);
for(int i=1;i<=m;++i)
e[i].u=read(),e[i].v=read(),e[i].g=lca(e[i].u,e[i].v),
e[i].len=dep[e[i].u]+dep[e[i].v]-2*dep[e[i].g]+1;
sort(e+1,e+m+1);
for(int i=1;i<=m;++i){
if(ask(e[i].u,e[i].v)>1){puts("No");return 0;}
++col,modify(e[i].u,e[i].v,col);
}puts("Yes");
}