codeforces #335div2 D. Lazy Student 构造

#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
",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。。。。

更新:第二种解法需要判重边。。。这样写起来更麻烦了。。。。是非常麻烦。。。。。

*/
View Code
没有AC不了的题,只有不努力的ACMER!
原文地址:https://www.cnblogs.com/--560/p/5036432.html