While studying combinatorial optimization, Lucas came across the notion of “laminar set family”. A subset family F of some set Ω is called laminar if and only if it does not contain an empty set and for any two distinct sets A, B ∈ F it is correct that either A ⊂ B or B ⊂ A or A ∩ B = ∅.
As an experienced problem setter Lucas always tries to apply each new piece of knowledge he gets as an idea for a programming competition problem. An area of his scientific interests covers recognition problems that usually sound like “Given some weird combinatorial property, check if the given structure satisfies it”.
Lucas believes that the perfect programming competition problem should contain a cactus a tree in it.
Trying to put together laminar sets and trees into a recognition problem, he finally came up with the following problem: given an undirected tree on n vertices and a family F = {F1, … , Fk} of sets, where Fi consists of all vertices belonging to the simple path between some two vertices ai and bi of the tree, check if the family F is a laminar family. Note that in this case Ω = V , and each Fi ⊆ V .
As you can see, Lucas had succeeded in suggesting this problem to the programming contest. Now it is up to you to solve it.
The first line of the input contains two integers n and f (1 ≤ n, f ≤ 100 000) — the number of vertices in the tree and the number of elements in a family F.
Next n−1 lines describe the tree structure. In the i-th line there are two integers ui and vi (1 ≤ ui, vi ≤ n,ui != vi) — the indices of the vertices that are connected by the i-th edge of the tree.
Next f lines describe the sets forming the family F. In the i-th line there are two integers ai and bi (1 ≤ ai, bi ≤ n), such that Fi consists of all vertices belonging to the simple path between vertices ai and bi in the tree (including ai and bi)
Output the only word “Yes” or “No” depending on whether or not the given set family is laminar.
Sample Input | Sample Output |
---|---|
4 2 1 2 2 3 2 4 1 2 4 2 | No |
6 5 1 2 2 3 3 4 5 6 5 2 2 1 6 6 1 4 3 4 4 1 | Yes |
给出一棵树的若干路径,判断它们两两间是否都存在包含关系或完全没有交点。
利用树链剖分维护树的点权,依次处理每条链。若链上的max=min则符合题意,将链上所有点权值+1,否则就是No。
处理链之前需要先排序,第一关键字为lca深度,第二关键字为链的长度。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#include <assert.h>
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef pair<int,int> pp;
const int maxn=100005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
int sz[maxn],son[maxn],fa[maxn][20],top[maxn],dep[maxn],dfn[maxn],head[maxn];
bool visit[maxn];
int num=0;
struct Edge {
int from,to,pre;
};
Edge edge[maxn*2];
void addedge(int from, int to) {
edge[num].from = from; edge[num].to = to; edge[num].pre = head[from];
head[from]=num++;
edge[num].from = to; edge[num].to = from; edge[num].pre = head[to];
head[to]=num++;
}
struct query{
int x,y,lca,len;
};
query a[maxn];
bool sortcmp(query aa,query bb) {
return dep[aa.lca] < dep[bb.lca] || (dep[aa.lca] == dep[bb.lca] && aa.len > bb.len);
}
int dfs(int now,int step) {
visit[now]=1;son[now]=-1;sz[now]=1;dep[now]=step;
int i;
for (i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (!visit[to]) {
fa[to][0]=now;
sz[now]+=dfs(to,step+1);
if (son[now]==-1||sz[to]>sz[son[now]]) son[now]=to;
}
}
return sz[now];
}
void dfs2(int now,int gr) {
top[now]=gr;
dfn[now]=++num;
visit[now]=1;
if (son[now]==-1) return;
dfs2(son[now],gr);
int i;
for (i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (!visit[to]) dfs2(to,to);
}
}
int findlca(int a,int b) {
int x=a,y=b,i;
if (dep[x]>dep[y]) swap(x,y);
for (i=18;i>=0;i--)
if (dep[fa[y][i]]>=dep[x]) y=fa[y][i];
if (y==x) return x;
for (i=18;i>=0;i--)
if (fa[y][i]!=fa[x][i]&&fa[x][i]!=0&&fa[y][i]!=0)
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
struct Tree {
int lc,rc,l,r,max,tag,min;
};
Tree tree[4*maxn];
bool cmp(Tree a,Tree b) {
if (a.max+a.tag>b.max+b.tag) return true; else return false;
}
bool cmp2(Tree a,Tree b) {
if (a.min+a.tag<b.min+b.tag) return true; else return false;
}
void pushup(int now) {
if (cmp(tree[tree[now].lc],tree[tree[now].rc]))
tree[now].max=tree[tree[now].lc].max+tree[tree[now].lc].tag;
else
tree[now].max=tree[tree[now].rc].max+tree[tree[now].rc].tag;
if (cmp2(tree[tree[now].lc],tree[tree[now].rc]))
tree[now].min=tree[tree[now].lc].min+tree[tree[now].lc].tag;
else
tree[now].min=tree[tree[now].rc].min+tree[tree[now].rc].tag;
}
void pushdown(int now) {
if (tree[now].tag==0) return;
tree[tree[now].lc].tag+=tree[now].tag;
tree[tree[now].rc].tag+=tree[now].tag;
tree[now].max+=tree[now].tag;tree[now].min+=tree[now].tag;
tree[now].tag=0;
}
void build(int now,int l,int r) {
tree[now].l=l;
tree[now].r=r;
tree[now].tag=0;
tree[now].max=tree[now].min=0;
if (l!=r) {
num++;
tree[now].lc=num;
build(num,l,(l+r)/2);
num++;
tree[now].rc=num;
build(num,(l+r)/2+1,r);
}
}
void update (int now,int l,int r,int c) {
if (tree[now].l>=l&&tree[now].r<=r) {
tree[now].tag+=c;
} else {
pushdown(now);
if (l<=(tree[now].l+tree[now].r)/2)
update(tree[now].lc,l,r,c);
if (r>(tree[now].l+tree[now].r)/2)
update(tree[now].rc,l,r,c);
pushup(now);
}
}
int findmax (int now,int l,int r) {
if (tree[now].l>=l&&tree[now].r<=r) {
return tree[now].max+tree[now].tag;
} else {
pushdown(now);
int ans=-inf;
if (l<=(tree[now].l+tree[now].r)/2)
ans=max(ans,findmax(tree[now].lc,l,r));
if (r>(tree[now].l+tree[now].r)/2)
ans=max(ans,findmax(tree[now].rc,l,r));
return ans;
}
}
int findmin (int now,int l,int r) {
if (tree[now].l>=l&&tree[now].r<=r) {
return tree[now].min+tree[now].tag;
} else {
//deleted pushdown
int ans=inf;
if (l<=(tree[now].l+tree[now].r)/2)
ans=min(ans,findmin(tree[now].lc,l,r));
if (r>(tree[now].l+tree[now].r)/2)
ans=min(ans,findmin(tree[now].rc,l,r));
return ans;
}
}
void modify(int u,int v,int val) {
int x=top[u],y=top[v];
while (x!=y) {
if (dep[x]<dep[y]) swap(x,y),swap(u,v);
update(1,dfn[x],dfn[u],val);
u=fa[x][0];
x=top[u];
}
if (dep[u]<dep[v]) swap(u,v);
update(1,dfn[v],dfn[u],val);
}
bool search(int u,int v) {
int x=top[u],y=top[v];
int mx,mn;mx=-1;mn=inf;
while (x!=y) {
if (dep[x]<dep[y]) swap(x,y),swap(u,v);
mx=max(mx,findmax(1,dfn[x],dfn[u]));
mn=min(mn,findmin(1,dfn[x],dfn[u]));
u=fa[x][0];
x=top[u];
}
if (dep[u]<dep[v]) swap(u,v);
mx=max(mx,findmax(1,dfn[v],dfn[u]));
mn=min(mn,findmin(1,dfn[v],dfn[u]));
return mx==mn;
}
int main() {
int n,q,x,y;
scanf("%d%d",&n,&q);
num=0;memset(head,-1,sizeof(head));
for (int i=1;i<n;i++) {
scanf("%d%d",&x,&y);
addedge(x,y);
}
num=0;
fa[1][0]=0;dep[0]=-1;
dfs(1,1);num=0;
for (int j=1;j<=18;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
mem0(visit);dfs2(1,1);
for (int i=1;i<=q;i++) {
scanf("%d%d",&x,&y);
a[i].x=x;a[i].y=y;
a[i].lca=findlca(x,y);
a[i].len=dep[x]+dep[y]-2*dep[a[i].lca];
}
num=1;
build(1,1,n);
sort(a+1,a+q+1,sortcmp);
for (int i=1;i<=q;i++) {
if (!search(a[i].x,a[i].y)) {
printf("No\n");return 0;
}
modify(a[i].x,a[i].y,1);
}
printf("Yes\n");
// system("pause");
return 0;
}