![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1<<29; int n,m; struct Edge { int w,is; int id; friend bool operator<(Edge A,Edge B) { return A.w==B.w?A.is>B.is:A.w<B.w; } };Edge e[maxn],ans[maxn]; bool cmp(Edge A,Edge B) { return A.id<B.id; } int main() { //freopen("in.txt","r",stdin); while(cin>>n>>m){ REP(i,1,m) scanf("%d%d",&e[i].w,&e[i].is),e[i].id=i; sort(e+1,e+m+1); int cur=1,cnt=0; int L=1,R=3; bool flag=1; REP(i,1,m){ if(e[i].is){ ans[++cnt]={cur,cur+1,e[i].id}; cur++; } else{ bool tag=0; //cout<<"L="<<L<<" R="<<R<<endl; if(R<=cur&&R-L>=2) tag=1; else{ while(R-L<=1&&R<=cur){ while(L>=1&&R-L<=1) L--; if(R-L>=2){ tag=1;break; } else R++; } } if(!tag){ flag=0;break; } ans[++cnt]={L,R,e[i].id}; L--; if(L<1) R++,L=R-2; } } sort(ans+1,ans+cnt+1,cmp); if(flag){ REP(i,1,cnt) printf("%d %d\n",ans[i].w,ans[i].is); } else puts("-1"); } return 0; } /** 构造法的题目比较自由,虽然变化多端,但是还是有一些技巧的。 构造的关键在于避开繁琐的情况,寻找一种尽可能简单又尽可能接近答案的情况,并加以证明。 本题中,给定一些边的信息(边权和是否在MST中),求构造出一个符合条件的图,若不存在输出-1。 由于边的顶点没给,所以符合条件的图不止一种,显然是构造的题目。 构造的方式千变万化,没有固定的答案,但是我们要尽可能找出比较容易的构造方式,这就需要优先找一些特殊情况。 显然,MST是链比树更容易构造,至于正确性,先不管。 再根据MST的性质,联系到kruskal,自然而然地要给边权排序。 这样解法就出来了: 从小到大遍历边,如果属于MST,直接加到链的末端,否则,在链上找两个点,由于边是从小到大添加的,所以随便 找连个点就行,但是要注意不能有重边,而且要避免重复遍历和漏遍历,所以遍历顺序很重要,前面的提交挂在第27个就是 因为遍历顺序不对,导致有些边没有遍历到,从而得出-1的情况。后来我想了一个解决办法,原来的遍历方式是直接划窗, 现在改成L向左划,R向右划,先划L再划R,这样就避免了漏遍历。 v8的解法: 还是从小到大排序 直接按度数维护点,如果不在MST上,每次取两个度数最小的点,连边,否则加入一个新点。 中间过程每个点的度数不超过cur-1表示有解。(简单图的每个点的度数不超过n-1). 这个正确性就显而易见了,,,,orz。。。。 更新:第二种解法需要判重边。。。这样写起来更麻烦了。。。。是非常麻烦。。。。。 */