生成树,2019NOI金牌营6,思维好题
作者:互联网
正题
因为这次比赛撞题了,我就凭借着我曾经的记忆慢慢的写出来了这一题。(现场做出来的是真的强
我们考虑先把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