NEERC-2017

A. Archery Tournament

用线段树套set维护横坐标区间内的所有圆,查询时在$O(\log n)$个set中二分查找即可。

时间复杂度$O(n\log^2n)$。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
#define rt 1,1,g
#define mid (l+r>>1)
#define lson ls,l,mid
#define rson rs,mid+1,r
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 2e6 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
struct AAA
{
    int y, x;
}a[N];
LL K(LL x)
{
    return x * x;
}
bool in_circle(int o1, int o2)
{
    int y1 = a[o1].y;
    int x1 = a[o1].x;
    int y2 = a[o2].y;
    int x2 = a[o2].x;
    return K(y1 - y2) + K(x1 - x2) < K(y2);
}
struct A
{
    int ask;
    int id;
    bool operator < (const A & b)const
    {
        if(ask && b.ask)
        {
            if(a[id].y != a[b.id].y)return a[id].y < a[b.id].y;
            else return id < b.id;
        }
        else if(!ask && !b.ask)
        {
            if(a[id].y != a[b.id].y)return a[id].y < a[b.id].y;
            else return id < b.id;
        }
        else if(ask && !b.ask)
        {
            if(in_circle(id, b.id))return 1;
            else
            {
                if(a[id].y != a[b.id].y)return a[id].y < a[b.id].y;
                else return id < b.id;
            }
        }
        else //if(!ask && b.ask)
        {
            if(in_circle(b.id, id))return 0;
            else
            {
                if(a[id].y != a[b.id].y)return a[id].y < a[b.id].y;
                else return id < b.id;
            }
        }
    }
};
struct Q
{
    int tp, y, x;
}q[N];
int v[N * 3]; int g;
set<A>sot[N * 4];
void build(int o, int l, int r)
{
    sot[o].clear();
    if(l == r)
    {
        return;
    }
    build(lson);
    build(rson);
}
int O, L, R;
void ins(int o, int l, int r)
{
    if(L <= l && r <= R)
    {
        sot[o].insert({0, O});
        return;
    }
    if(L <= mid)ins(lson);
    if(R > mid)ins(rson);
}
void del(int o, int l, int r)
{
    if(L <= l && r <= R)
    {
        sot[o].erase({0, O});
        return;
    }
    if(L <= mid)del(lson);
    if(R > mid)del(rson);
}
int P;
int find(int o, int l, int r)
{
    auto it = sot[o].lower_bound({1, 0});
    if(it != sot[o].end())
    {
        int aim = it->id;
        if(in_circle(0, aim))return aim;
    }
    if(l == r)return 0;
    if(P <= mid)return find(lson);
    else return find(rson);
}
int main()
{
	while(~scanf("%d", &n))
	{
        g = 0;
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d%d%d", &q[i].tp, &q[i].x, &q[i].y);
            if(q[i].tp == 1)
            {
                q[i].tp = i;
                a[i].y = q[i].y; a[i].x = q[i].x;
                v[++g] = q[i].x - q[i].y;
                v[++g] = q[i].x + q[i].y;
            }
            else
            {
                q[i].tp = 0;
                v[++g] = q[i].x;
            }
        }
        sort(v + 1, v + g + 1);
        g = unique(v + 1, v + g + 1) - v - 1;
        build(rt);
        for(int i = 1; i <= n; ++i)
        {
            if(q[i].tp)
            {
                O = q[i].tp;
                L = lower_bound(v + 1, v + g + 1, q[i].x - q[i].y) - v + 1;
                R = lower_bound(v + 1, v + g + 1, q[i].x + q[i].y) - v - 1;
                if(L <= R)
                {
                    ins(rt);
                }
            }
            else
            {
                P = lower_bound(v + 1, v + g + 1, q[i].x) - v;
                a[0].y = q[i].y; a[0].x = q[i].x;
                O = find(rt);
                if(O)
                {
                    printf("%d\n", O);
                    L = lower_bound(v + 1, v + g + 1, q[O].x - q[O].y) - v + 1;
                    R = lower_bound(v + 1, v + g + 1, q[O].x + q[O].y) - v - 1;
                    del(rt);
                }
                else puts("-1");
            }
        }
	}
	return 0;
}
/*
【trick&&吐槽】
4
1 0 12
1 24 10
1 12 3
2 16 14

8
1 0 12
2 -11 22
1 24 10
1 12 3
2 12 12
2 16 14
1 28 15
2 3 6

【题意】


【分析】


【时间复杂度&&优化】


*/

  

B. Box

分类讨论。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int a[3];
int w, h;
int ww, hh;
bool check4()
{
    return ww <= w && hh <= h;
}
bool check3()
{
    //1
    ww = a[0] * 0 + a[1] * 2 + a[2] * 2;
    hh = a[0] * 1 + a[1] * 0 + a[2] * 2;
    if(check4())return 1;

    //2
    ww = a[0] * 0 + a[1] * 2 + a[2] * 2;
    hh = a[0] * 1 + a[1] * 1 + a[2] * 1;
    if(check4())return 1;

    //3
    ww = a[0] * 1 + a[1] * 1 + a[2] * 3;
    hh = a[0] * 1 + a[1] * 1 + a[2] * 0;
    if(check4())return 1;

    //4
    ww = a[0] * 1 + a[1] * 1 + a[2] * 2;
    hh = a[0] * 1 + a[1] * 1 + a[2] * 1;
    if(check4())return 1;

    //5
    ww = a[0] * 1 + a[1] * 2 + a[2] * 1;
    hh = a[0] * 1 + a[1] * 0 + a[2] * 2;
    if(check4())return 1;

    //6
    ww = a[0] * 2 + a[1] * 1 + a[2] * 1;
    hh = a[0] * 1 + a[1] * 1 + a[2] * 1;
    if(check4())return 1;

    //7
    ww = a[0] * 2 + a[1] * 1 + a[2] * 0;
    hh = a[0] * 1 + a[1] * 1 + a[2] * 2;
    if(check4())return 1;

    return 0;
}
bool check2()
{
    sort(a, a + 3);
    do
    {
        if(check3())return 1;
    }while(next_permutation(a, a + 3));
    return 0;
}
bool check()
{
    if(check2())return 1;
    swap(w, h);
    if(check2())return 1;
    else return 0;
}
int main()
{
	while(~scanf("%d%d%d", &a[0], &a[1], &a[2]))
	{
	    scanf("%d%d", &w, &h);
	    puts(check() ? "Yes" : "No");
	}
	return 0;
}

/*
【trick&&吐槽】


【题意】


【分析】


【时间复杂度&&优化】


*/

  

C. Connections

考虑强连通分量的Kosaraju算法,会发现只有$2(n-1)$条边是有用的,符合题目中保留$2n$条边要求。

#include<cstdio>
const int N=300010;
int Case,n,m,i,x,y,cnt,use[N],g[2][N],nxt[2][N],v[2][N],ed,q[N],t,vis[N],e[N][2];
inline void add(int x,int y){
	v[0][++ed]=y;nxt[0][ed]=g[0][x];g[0][x]=ed;
	v[1][ed]=x;nxt[1][ed]=g[1][y];g[1][y]=ed;
}
void dfs1(int x){
	vis[x]=1;
	for(int i=g[0][x];i;i=nxt[0][i])if(!vis[v[0][i]])use[i]=1,dfs1(v[0][i]);
	q[++t]=x;
}
void dfs2(int x){
	vis[x]=0;
	for(int i=g[1][x];i;i=nxt[1][i])if(vis[v[1][i]])use[i]=1,dfs2(v[1][i]);
}
int main(){
	scanf("%d",&Case);
	while(Case--){
		scanf("%d%d",&n,&m);
		for(ed=0,i=1;i<=n;i++)vis[i]=g[0][i]=g[1][i]=0;
		for(i=1;i<=m;i++){
			scanf("%d%d",&x,&y);
			e[i][0]=x,e[i][1]=y;
			add(x,y);
			use[i]=0;
		}
		for(t=0,i=1;i<=n;i++)if(!vis[i])dfs1(i);
		for(i=n;i;i--)if(vis[q[i]])dfs2(q[i]);
		cnt=n*2;
		for(i=1;i<=m;i++)if(use[i])cnt--;
		for(i=1;i<=m;i++)if(!use[i]&&cnt>0)use[i]=1,cnt--;
		for(i=1;i<=m;i++)if(!use[i])printf("%d %d\n",e[i][0],e[i][1]);
	}
}
/*
111
4 9
1 2
1 3
2 3
2 4
3 2
3 4
4 1
4 2
4 3
*/

  

D. Designing the Toy

斜着构造然后再补充剩下部分即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 105, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int A, B, C;
int a[3];
bool v[N][N];
struct AAA
{
    AAA(int x, int y, int z)
    {
        v[0] = x;
        v[1] = y;
        v[2] = z;
    }
    int v[3];
};
vector<AAA>vt;
void SWAP(int x, int y)
{
    int g = vt.size();
    for(int i = 0; i < g; ++i)
    {
        swap(vt[i].v[x], vt[i].v[y]);
    }
}
int main()
{
	while(~scanf("%d%d%d", &A, &B, &C))
	{
        a[0] = A;
        a[1] = B;
        a[2] = C;
        sort(a, a + 3);
        if(a[0] * a[1] < a[2])
        {
            puts("-1");
            continue;
        }
        else
        {
            vt.clear();
            MS(v, 0);
            int cnt = a[2] - a[1];
            for(int i = 1; i <= a[0]; ++i)
            {
                //vt.push_back({i, i, 1});
                vt.push_back(AAA(i, i, 1));
                v[i][i] = 1;
            }
            for(int i = a[0] + 1; i <= a[1]; ++i)
            {
                //vt.push_back({1, i, 1});
                vt.push_back(AAA(1, i, 1));
                v[1][i] = 1;
            }
            for(int i = 1; i <= a[0]; ++i)
            {
                for(int j = 1; j <= a[1]; ++j)
                {
                    if(v[i][j] == 0 && cnt)
                    {
                        --cnt;
                        //vt.push_back({i, j, 1});
                        vt.push_back(AAA(i, j, 1));
                        v[i][j] = 1;
                    }
                }
            }
        }
        if(A >= max(B, C))
        {
            if(C >= B);
            else SWAP(0, 1);
        }
        else if(C >= max(A, B))
        {
            SWAP(0, 2);
            if(A >= B);
            else SWAP(1, 2);
        }
        else
        {
            SWAP(1, 2);
            if(C >= A);
            else SWAP(0, 2);
        }
        printf("%d\n", vt.size());
        for(auto it : vt)
        {
            printf("%d %d %d\n", it.v[0], it.v[1], it.v[2]);
        }
	}
	return 0;
}

/*
【trick&&吐槽】


【题意】


【分析】


【时间复杂度&&优化】


*/

  

E. Easy Quest

依次考虑每个事件,维护每种数字出现次数和待定的数字个数,当数字不够时确定一个数字。

#include<cstdio>
const int N=100000;
int n,i,x,c[N],cnt,m,q[N];
int main(){
  scanf("%d",&n);
  for(i=1;i<=n;i++){
    scanf("%d",&x);
    if(x>0)c[x]++;
    else if(x==0){
      cnt++;
    }else{
      if(c[-x])c[-x]--;
      else if(cnt){
        q[++m]=-x;
        cnt--;
      }else return puts("No"),0;
    }
  }
  puts("Yes");
  for(i=1;i<=m;i++)printf("%d ",q[i]);
  while(cnt--)printf("1 ");
}

  

F. The Final Level

贪心选离目的地较近的那一维坐标靠近即可。

 

G. The Great Wall

二分答案,转化为统计有多少方案的权值和不超过$mid$。

整理出式子后可以通过排序后双指针+树状数组维护。

时间复杂度$O(n\log^2n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=30010;
int n,len,i;
int m;
ll K,a[N],b[N],c[N],L,R,ANS,MID;
ll f[N],g[N];
int q[N],p[N],bit[N];
inline bool cmp1(int x,int y){return f[x]<f[y];}
inline bool cmp2(int x,int y){return g[x]<g[y];}
inline void add(int x){for(;x<=n;x+=x&-x)bit[x]++;}
inline int ask(int x){int t=0;for(;x;x-=x&-x)t+=bit[x];return t;}
inline int sum(int l,int r){
	l=max(l,1);
	r=min(r,n);
	if(l>r)return 0;
	return ask(r)-ask(l-1);
}
ll cal(){
	int i,j;
	m=n-len+1;
	for(i=1;i<=m;i++){
		f[i]=a[i-1]+b[i+len-1]-b[i-1]-a[i+len-1];
		q[i]=i;
	}
	sort(q+1,q+m+1,cmp1);
	ll ret=0;
	for(i=1;i<=n;i++)bit[i]=0;
	for(i=m,j=1;i;i--){
		while(j<=m&&f[q[i]]+f[q[j]]<=MID)add(q[j++]);
		ret+=sum(q[i]+len,m);
	}
	for(i=1;i<=m;i++){
		f[i]=a[i-1]-b[i-1]+c[i+len-1]-b[i+len-1];
		g[i]=b[i-1]-c[i-1]+b[i+len-1]-a[i+len-1];
		q[i]=p[i]=i;
	}
	sort(q+1,q+m+1,cmp1);
	sort(p+1,p+m+1,cmp2);
	for(i=1;i<=n;i++)bit[i]=0;
	for(i=m,j=1;i;i--){
		while(j<=m&&f[q[i]]+g[p[j]]<=MID)add(p[j++]);
		ret+=sum(q[i]+1,q[i]+len-1);
	}
	return ret;
}
int main(){
	scanf("%d%d%lld",&n,&len,&K);
	for(i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]+=a[i-1];
	for(i=1;i<=n;i++)scanf("%lld",&b[i]),b[i]+=b[i-1];
	for(i=1;i<=n;i++)scanf("%lld",&c[i]),c[i]+=c[i-1];
	L=0,R=c[n];
	while(L<=R){
		MID=(L+R)>>1;
		ll tmp=cal();
		if(tmp>=K)R=(ANS=MID)-1;else L=MID+1;
	}
	printf("%lld",ANS+a[n]);
}
/*
4 2 3
1 2 3 4
3 3 5 5
7 7 7 7
*/

  

H. Hack

留坑。

 

I. Interactive Sort

考虑将偶数划分成若干不可区分大小的集合,将这些集合从小到大排序。一开始所有偶数形成一个不可区分大小的集合。

依次考虑每个奇数,将其在这些集合中二分查找,从对应集合中任取一个数进行比较,得到它大约落在哪两个集合中,再暴力遍历两个集合中所有数字,将对应集合划分成两半。同时,这个过程可以得出有多少偶数小于当前奇数,故可以确定出该奇数。

那么考虑完所有奇数后,所有偶数也就排好了序,因为数据随机,因此可以认为每次都是均分的,比较次数$O(n\log n)$。

#include<cstdio>
#include<vector>
using namespace std;
const int N=11111,K=2;
int n,m,i,j,k;
int cnt;
int cp;
vector<int>a[N];
int fin[N];
int q[N];
//+ -
vector<int>ans;
inline bool cmp(int x,int y){//x<y?
	if(x>0){
		printf("? %d %d\n",x,-y);
		fflush(stdout);
		char op[9];
		scanf("%s",op);
		return op[0]=='<';
	}else{
		printf("? %d %d\n",y,-x);
		fflush(stdout);
		char op[9];
		scanf("%s",op);
		return op[0]=='>';
	}
}
int flag,c0,c1;
int result[N];
int num[N];
inline void gao(int x,int o){
	c0=c1=0;
	int cur=a[q[x]].size();
	for(int i=0;i<cur;i++){
		int y=a[q[x]][i];
		num[i]=y;
		result[i]=cmp(y,o);
		if(result[i]){
			c0++;
		}else{
			c1++;
		}
	}
	if(!c1){
		flag=1;
		return;
	}
	if(!c0){
		flag=-1;
		return;
	}
	flag=0;
	cp++;
	for(int i=cp;i>x+1;i--)q[i]=q[i-1];
	q[x+1]=++cnt;
	a[cnt].clear();
	a[q[x]].clear();
	for(int i=0;i<cur;i++)if(result[i])a[q[x]].push_back(num[i]);
	else a[cnt].push_back(num[i]);
}
inline void gao2(int x,int o){
	int t=cmp(a[q[x]][0],o);
	if(t){
	  flag=1;
	  return;
	}else{
      flag=-1;
      return;
	}
}
int main(){
	scanf("%d",&n);
	if(n==1){
		puts("! 1");
		fflush(stdout);
		return 0;
	}
	if(n==2){
		puts("! 2 1");
		fflush(stdout);
		return 0;
	}
	//even
	//odd
	m=n/2;
	
	
	//use odd to sort even
	cnt=1;
	cp=1;
	a[1].clear();
	for(i=1;i<=m;i++)a[1].push_back(i);
	q[1]=1;
	for(i=1;i<=n-m;i++){
		int l=1,r=cp;
		while(l+K<=r){
			int mid=(l+r)>>1;
			gao2(mid,-i);
			if(flag<0)r=mid;else l=mid;
		}
		while(l<=r){
			int mid=(l+r)>>1;
			gao(mid,-i);
			if(flag==0)break;
			if(flag<0)r=mid-1;else l=mid+1;
		}
		l=max(l-2,1);
		while(l<=cp){
          gao2(l,-i);
          if(flag>0)l++;else break;
		}
		int res=0;
		for(j=1;j<l;j++)res+=a[q[j]].size();
		fin[m+i]=res*2+1;
	}
	int k=0;
	for(i=1;i<=cp;i++){
		for(j=0;j<a[q[i]].size();j++){
			k+=2;
			fin[a[q[i]][j]]=k;
		}
	}
	
	
	printf("!");
	for(i=1;i<=n;i++)printf(" %d",fin[i]);
	puts("");
	fflush(stdout);
}

  

J. Journey from Petersburg to Moscow

若经过至多$k$条边,则答案显然包含在$1$到$n$直接的最短路之中。

否则至少经过$k$条边,枚举最大$k$条边中最小的那一条边的权值$x$,将所有边权值重置为$\max(0,w-x)$,求出$1$到$n$的最短路$d$,则可以用$d+kx$更新答案。这是因为如果此时求出的最短路$d$中边数不够$k$,那么$d+kx$必然不优;而如果收费的边超过$k$条,则减去的$x$过小,也会造成答案不优,因此一定存在一个$x$使得刚好取到最优解。

时间复杂度$O(m^2\log m)$。

#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<ll,int>P;
const int N=3010;
const ll inf=1LL<<60;
int n,m,K,i,g[N],v[N<<1],w[N<<1],nxt[N<<1],ed;
int lim,W;
ll d[N];
ll ans;
priority_queue<P,vector<P>,greater<P> >q;
inline void add(int x,int y,int z){
	v[++ed]=y;
	w[ed]=z;
	nxt[ed]=g[x];
	g[x]=ed;
}
struct E{int x,y,z;}e[N];
inline bool cmp(const E&a,const E&b){return a.z<b.z;}
inline void ext(int x,ll y){
	if(d[x]>y){
		q.push(P(d[x]=y,x));
	}
}
inline void dij(){
	int i,j;
	for(i=1;i<=n;i++)d[i]=inf;
	ext(1,0);
	while(!q.empty()){
		P t=q.top();q.pop();
		if(d[t.second]<t.first)continue;
		for(int i=g[t.second];i;i=nxt[i]){
			ext(v[i],t.first+max(w[i]-W,0));
		}
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&K);
	for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
	sort(e+1,e+m+1,cmp);
	ed=1;
	for(i=1;i<=m;i++)add(e[i].x,e[i].y,e[i].z),add(e[i].y,e[i].x,e[i].z);
	dij();
	ans=d[n];
	for(lim=1;lim<=m;lim++){
		W=e[lim].z;
		dij();
		ans=min(ans,d[n]+1LL*W*K);
	}
	printf("%lld",ans);
}

  

K. Knapsack Cryptosystem

留坑。

 

L. Laminar Family

首先将所有未被任何一条树链经过的树边删除,那么剩下的点度数都不能超过$2$,否则必然非法。

那么剩下的图每个连通块都只可能是链,是经典序列问题,把所有区间按左端点排序后单调栈判断即可。

时间复杂度$O(f\log n)$。

#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int N=100010;
int n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
int f[N],son[N],size[N],top[N],d[N];
int e[N][2];
int tag[N];
int deg[N];
int G[N],V[N<<1],NXT[N<<1],ED;
bool vis[N];
int ge[N],vv[N],nxte[N],ee;
void NIE(){
	puts("No");
	exit(0);
}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
inline void adde(int x,int y){vv[++ee]=y;nxte[ee]=ge[x];ge[x]=ee;}
void dfs(int x){
	d[x]=d[f[x]]+1;
	size[x]=1;
	for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
		f[v[i]]=x;
		dfs(v[i]);
		size[x]+=size[v[i]];
		if(size[v[i]]>size[son[x]])son[x]=v[i];
	}
}
void dfs2(int x,int y){
	top[x]=y;
	if(son[x])dfs2(son[x],y);
	for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]&&v[i]!=son[x])dfs2(v[i],v[i]);
}
inline void addedge(int x,int y){
	//printf("! %d %d\n",x,y);
	deg[x]++;deg[y]++;
	V[++ED]=y;NXT[ED]=G[x];G[x]=ED;
	V[++ED]=x;NXT[ED]=G[y];G[y]=ED;
}
void dfs3(int x){
	for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
		dfs3(v[i]);
		tag[x]+=tag[v[i]];
	}
	if(x>1&&tag[x])addedge(x,f[x]);
}
inline int lca(int x,int y){
	while(top[x]!=top[y]){
		if(d[top[x]]<d[top[y]])swap(x,y);
		x=f[top[x]];
	}
	return d[x]<d[y]?x:y;
}
int q[N],pos[N];
int all;
struct Seg{
	int l,r;
}seg[N],st[N];
inline bool cmp(const Seg&a,const Seg&b){
	if(a.l!=b.l)return a.l<b.l;
	return a.r>b.r;
}
inline void append(int l,int r){
	if(l>r)swap(l,r);
	seg[++all].l=l;
	seg[all].r=r;
}
inline void check(){
	if(all<=1)return;
	sort(seg+1,seg+all+1,cmp);
	int i;
	int t=0;
	for(i=1;i<=all;i++){
		while(t){
			if(seg[i].r<=st[t].r)break;
			if(seg[i].l<=st[t].r)NIE();
			t--;
		}
		st[++t]=seg[i];
	}
}
inline void solve(int S){
	int cnt=0;
	int i,j;
	while(1){
		vis[S]=1;
		q[++cnt]=S;
		int t=0;
		for(i=G[S];i;i=NXT[i])if(!vis[V[i]]){
			t=V[i];
		}
		if(!t)break;
		S=t;
	}
	//for(i=1;i<=cnt;i++)printf("%d ",q[i]);puts("");
	for(i=1;i<=cnt;i++)pos[q[i]]=i;
	all=0;
	for(i=1;i<=cnt;i++){
		for(j=ge[q[i]];j;j=nxte[j]){
			append(pos[q[i]],pos[vv[j]]);
		}
	}
	check();
}
int main(){
	scanf("%d%d",&n,&m);
	for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	dfs(1);
	dfs2(1,1);
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		e[i][0]=x,e[i][1]=y;
		int z=lca(x,y);
		tag[x]++;
		tag[y]++;
		tag[z]-=2;
		adde(x,y);
	}
	dfs3(1);
	for(i=1;i<=n;i++)if(deg[i]>2)NIE();
	for(i=1;i<=n;i++)if(deg[i]==1&&!vis[i])solve(i);
	puts("Yes");
}
/*
4 2
1 2
2 3
2 4
1 2
4 2



6 5
1 2
2 3
3 4
5 6
5 2
2 1
6 6
1 4
3 4
4 1
*/

 

posted @ 2017-12-10 02:10  Claris  阅读(2595)  评论(1编辑  收藏  举报