zoukankan      html  css  js  c++  java
  • NEERC-2017

    A. Archery Tournament

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

    时间复杂度$O(nlog^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
    ", 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
    ",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
    ", vt.size());
            for(auto it : vt)
            {
                printf("%d %d %d
    ", 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(nlog^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(nlog 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
    ",x,-y);
    		fflush(stdout);
    		char op[9];
    		scanf("%s",op);
    		return op[0]=='<';
    	}else{
    		printf("? %d %d
    ",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^2log 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(flog 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
    ",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
    */
    
  • 相关阅读:
    Linux 查看CPU信息,机器型号,内存等信息
    TCPdump抓包命令详解
    nginx https 转发
    滚动效果
    phpexcel中文手册(转)
    Java数组操作十大方法 (转)
    ajax防止重复提交
    信用评分卡(A卡/B卡/C卡)的模型简介及开发流程|干货
    求方差分析与两样本T检验 区别
    互联网运营中的10大数据分析方法
  • 原文地址:https://www.cnblogs.com/clrs97/p/8015864.html
Copyright © 2011-2022 走看看