其他分享
首页 > 其他分享> > 生成树,2019NOI金牌营6,思维好题

生成树,2019NOI金牌营6,思维好题

作者:互联网

正题

       因为这次比赛撞题了,我就凭借着我曾经的记忆慢慢的写出来了这一题。(现场做出来的是真的强

       Portal

       我们考虑先把1到n的边先建出来,如果已经有n-1条黑边或者白边,那么就直接输出。

       否则就存在一个点使得它的两边一边是黑边都是白边。

       可以直接问一下连接两边的点的边,直接把这条边建出来,那么无论外面是白树还是黑树,都可以走到当前点。

       接着我们拿这个点旁边的两个点进去深搜,如果其中的一个点的旁边的两个点没有联通,那么肯定是一条黑边一条白边,再不断问下去,直到联通为止。

       在这个过程中,我们可以用链表来维护这个左右点。

#include<map>
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;

int n,m,tot1,tot2;
map<pair<int,int>,int> f;
long long X,Y,Z;
long long p[500010];
int w[500010],b[500010];
struct edge{
	int x,y;
}blk[500010],wht[500010];
int las[500010],nex[500010];

int ask_edge(int a,int b){
	if(f[make_pair(a,b)]) return f[make_pair(a,b)];
	if((min(a,b)*X+max(a,b)*Y)%Z<(p[a]+p[b])) return 2;
	else return 1;
}

int findpa(int*f,int x){
	if(f[x]!=x) return f[x]=findpa(f,f[x]);
	return x;
}

void update(int x,int y,int t){
	if(t==1) b[findpa(b,x)]=findpa(b,y),blk[++tot1]=(edge){x,y};
	else w[findpa(w,x)]=findpa(w,y),wht[++tot2]=(edge){x,y};
}

bool insame(int x,int y){
	int fx=findpa(w,x),fy=findpa(w,y);
	if(fx==fy) return true;
	fx=findpa(b,x);fy=findpa(b,y);
	if(fx==fy) return true;
	return false;
}

void dfs(int l,int r){
	if(!insame(las[l],r)) update(las[l],r,ask_edge(las[l],r)),nex[las[l]]=r,las[r]=las[l],dfs(las[l],r);
	else if(!insame(l,nex[r])) update(l,nex[r],ask_edge(l,nex[r])),nex[l]=nex[r],las[nex[r]]=l,dfs(l,nex[r]);
}

int main(){
	scanf("%d %d",&n,&m);
	int x,y,c;
	for(int i=1;i<=m;i++){
		scanf("%d %d %d",&x,&y,&c);
		if(c==0) c=2;
		f[make_pair(x,y)]=c;f[make_pair(y,x)]=c;
	}
	scanf("%lld %lld %lld",&X,&Y,&Z);
	for(int i=1;i<=n;i++) scanf("%lld",&p[i]);
	for(int i=1;i<=n;i++) b[i]=w[i]=i;
	las[1]=n;for(int i=2;i<=n;i++) las[i]=i-1;
	nex[n]=1;for(int i=1;i<n;i++) nex[i]=i+1;
	for(int i=1;i<=n;i++) update(las[i],i,ask_edge(las[i],i));
	if(tot1>=n-1) for(int i=1;i<=n-1;i++) printf("%d %d\n",blk[i].x,blk[i].y);
	else if(tot2>=n-1) for(int i=1;i<=n-1;i++) printf("%d %d\n",wht[i].x,wht[i].y);
	if(tot1>=n-1 || tot2>=n-1) return 0;
	for(int i=1;i<=n;i++){
		if(insame(las[i],nex[i])) continue;
		update(las[i],nex[i],ask_edge(las[i],nex[i]));
		if(tot1==n-1 || tot2==n-1) break;
		nex[las[i]]=nex[i],las[nex[i]]=las[i];
		dfs(las[i],nex[i]);
	}
	if(tot1>=n-1) for(int i=1;i<=n-1;i++) printf("%d %d\n",blk[i].x,blk[i].y);
	else if(tot2>=n-1) for(int i=1;i<=n-1;i++) printf("%d %d\n",wht[i].x,wht[i].y);
}

 

标签:tot2,int,白边,好题,long,2019NOI,500010,include,金牌
来源: https://blog.csdn.net/Deep_Kevin/article/details/95030991