zoukankan      html  css  js  c++  java
  • CF1477D. Nezzar and Hidden Permutations

    给出一堆边(u,v),你需要构造出排列(p,q),满足((p_u-p_v)(q_u-q_v)>0),最大化(sum[p_i eq q_i])

    (nle 5*10^5)


    神仙构造。

    当一个点(i)的度数为(n-1)时,这个点一定满足(p_i=q_i)

    于是得到了上界为(n-度数为n-1的点数),下面给出方法压到这个上界:

    把度数小于(n-1)的点分成若干组,每组(S)满足:(|S|>1,exist xin S,forall y eq x,yin S,(x,y) otin E)。这个时候可以把(y)((1,2),(2,3),dots,(k,k+1))表示,(x)((k+1,1))表示。

    可以发现这时候(S)内部的点之间一定满足限制,由于用到的数字是连续的所以(S)内外的点之间也满足限制。

    如何找到一种分组方式:建出反图(不需要全部建出,只需要随便连少量的边。我的做法是找出编号最小的和当前点没有边的点,连这样一条边。),贪心随便找一个匹配,使得任何边相连的两个点至少有个被匹配覆盖。匹配中的每个点维护个点集。如果一个点不在匹配中,就把它丢到连向的任意一个点(一定在匹配内)的点集。

    考虑匹配中的一条边的两个端点,如果至少一个点集为空,则直接分成一组;否则,每个端点和各自的点集分为一组。


    using namespace std;
    #include <bits/stdc++.h>
    #define N 500005
    int n,m;
    set<int> e[N];
    int d[N];
    int p[N],q[N];
    int to[N];
    int bel[N];
    vector<int> vec[N];
    int main(){
    //	freopen("in.txt","r",stdin);
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d%d",&n,&m);
    		for (int i=1;i<=n;++i)
    			e[i].clear();
    		memset(d,0,sizeof(int)*(n+1));
    		for (int i=1;i<=m;++i){
    			int u,v;
    			scanf("%d%d",&u,&v);
    			e[u].insert(v);
    			e[v].insert(u);
    			d[u]++,d[v]++;
    		}
    		memset(p,0,sizeof(int)*(n+1));
    		memset(q,0,sizeof(int)*(n+1));
    		for (int i=1;i<=n;++i)
    			if (d[i]==n-1)
    				p[i]=q[i]=-1;
    			else{
    				for (int j=1;j<=n;++j)
    					if (j!=i && e[i].find(j)==e[i].end()){
    						to[i]=j;
    						break;
    					}
    			}
    		for (int i=1;i<=n;++i)
    			vec[i].clear();
    		memset(bel,0,sizeof(int)*(n+1));
    		for (int i=1;i<=n;++i){
    			if (d[i]==n-1) continue;
    			if (!bel[i] && !bel[to[i]])
    				bel[i]=to[i],bel[to[i]]=i;
    		}
    		for (int i=1;i<=n;++i)
    			if (d[i]!=n-1 && bel[i]==0)
    				vec[to[i]].push_back(i);
    		int c=0;
    		for (int i=1;i<=n;++i){
    			if (d[i]==n-1) continue;
    			if (bel[i] && i<bel[i]){
    				int x=i,y=bel[i];
    				if (vec[x].empty())
    					swap(x,y);
    				if (vec[x].empty()){
    					p[x]=c+1,q[x]=c+2;
    					p[y]=c+2,q[y]=c+1;
    					c+=2;
    				}
    				else{
    					if (vec[y].empty()){
    						int t=c;
    						++t,p[y]=t,q[y]=t+1;
    						for (int j=0;j<vec[x].size();++j)
    							++t,p[vec[x][j]]=t,q[vec[x][j]]=t+1;
    						++t,p[x]=t,q[x]=c+1;
    						c=t;
    					}
    					else{
    						int t=c;
    						for (int j=0;j<vec[x].size();++j)
    							++t,p[vec[x][j]]=t,q[vec[x][j]]=t+1;
    						++t,p[x]=t,q[x]=c+1;
    						c=t;
    						for (int j=0;j<vec[y].size();++j)
    							++t,p[vec[y][j]]=t,q[vec[y][j]]=t+1;
    						++t,p[y]=t,q[y]=c+1;
    						c=t;
    					}
    				}
    			}
    		}
    		for (int i=1;i<=n;++i)
    			if (d[i]==n-1)
    				p[i]=q[i]=++c;
    		for (int i=1;i<=n;++i) printf("%d ",p[i]);printf("
    ");
    		for (int i=1;i<=n;++i) printf("%d ",q[i]);printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Python解释器相关知识
    简单了解下Flask
    Scoket编程
    __file__的作用
    jquery编写可折叠列表
    浑浑噩噩的一天
    js实现杨辉三角
    js闭包
    python读取word表格
    HTMLTestRunner报告
  • 原文地址:https://www.cnblogs.com/jz-597/p/14347077.html
Copyright © 2011-2022 走看看