zoukankan      html  css  js  c++  java
  • [CF GYM101741E] Code-Cola Plants

    前言

    新性质get!

    题目

    CF

    多组数据,给一张 (n) 个点,(m) 条有向边的 DAG,两个点 (a,b)。试寻找两组路径:

    • 两组路径都含有且仅含有 (n-1) 条不同的边。
    • 从节点 (a) 经第一组路径可以到达所有点。
    • 从所有点经第二组路径可以到达节点 (b)

    (2le sum nle 5 imes 10^5;1le sum mle 10^6;1le a,ble n.)

    讲解

    首先我们转换题意,第一组路径是使得除节点 (a) 外的入度为 (1)(n-1) 条边,第二组路径是使得除节点 (b) 外的出度为 (1)(n-1) 条边。

    由于不能共用边,自然可以想到二分图匹配。左边有 (2n-2) 个点,表示每个点的入度和出度,右边有 (m) 个点,表示这 (m) 条边,显然每条边匹配一个出度点和一个入度点。

    我们要做的就是二分图匹配,但是无论是匈牙利还是网络流,在如此大的数据范围下都不太能跑,于是考虑挖掘性质。

    发现右边其实就只有两条边,考虑直接把右边的点删掉,左边直接连边,由于右边的点度数至多为2,所以最后连出来是基环树森林。是基环树这事我想了好久qwq

    然后直接在基环树上DP就好了,或者说贪心?

    时间复杂度 (O(n+m))

    代码

    注意初始化!!!
    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 1000005;
    int n,m,A,B;
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int head[MAXN],tot;
    struct edge
    {
    	int v,nxt;
    }e[MAXN<<1];
    void Add_Edge(int x,int y)
    {
    	e[++tot] = edge{y,head[x]};
    	head[x] = tot;
    }
    void Add_Double_Edge(int x,int y)
    {
    	Add_Edge(x,y);
    	Add_Edge(y,x);
    }
    int ans[MAXN];
    bool vis[MAXN],un[MAXN];
    void dfs(int x,int ifa)
    {
    	vis[x] = 1;
    	for(int i = head[x],v; i ;i = e[i].nxt)
    	{
    		v = e[i].v;
    		if((i^1) == ifa) continue;
    		if(!vis[v]) dfs(v,i);
    		if(un[x]) continue;
    		if((i>>1)^ans[v]) ans[x] = i>>1;
    	}
    	if(!ans[x] && !un[x] && ifa) ans[x] = ifa>>1;//have no alternative
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	while(~scanf("%d",&n))
    	{
    		m = Read(); A = Read(); B = Read(); tot = 1;
    		for(int i = (n<<1);i >= 1;-- i) ans[i] = head[i] = 0,vis[i] = un[i] = 0;
    		for(int i = 1,u,v;i <= m;++ i)
    		{
    			u = Read(),v = Read();
    			Add_Double_Edge(u,v+n);
    		}
    		un[A+n] = un[B] = 1;//A:no in,B: no out 
    		for(int i = 1;i <= (n<<1);++ i) 
    			if(!vis[i]) dfs(i,0);
    		bool no = 0;
    		for(int i = 1;i <= (n<<1);++ i)
    			if(!un[i] && !ans[i])
    			{
    				no = 1;
    				break;
    			}
    		if(no) printf("NO
    ");
    		else 
    		{
    			printf("YES
    ");
    			for(int i = n+1;i <= (n<<1);++ i) if(!un[i]) Put(ans[i],' '); putchar('
    ');
    			for(int i = 1;i <= n;++ i) if(!un[i]) Put(ans[i],' '); putchar('
    ');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    16. 3Sum Closest
    17. Letter Combinations of a Phone Number
    20. Valid Parentheses
    77. Combinations
    80. Remove Duplicates from Sorted Array II
    82. Remove Duplicates from Sorted List II
    88. Merge Sorted Array
    257. Binary Tree Paths
    225. Implement Stack using Queues
    113. Path Sum II
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15478001.html
Copyright © 2011-2022 走看看