[Sdwc] 线段

线段有如下两类特点:
1 x y, 表示第 x 条线段和第 y 条线段相交 (相交在这里指至少有一个公共点)
2 x y,表示第 x 条线段在第 y 条线段的左边,且它们不相交。
共有 m 个特点,每个特点都是如上两类之一。
通过这些特点推理得到每条线段的端点。

x与y相交说明a[x]<b[y]且a[y]<b[x]
x在y左边说明b[x]<a[y]
每条线段x还应满足a[x]<b[x]
这相当于一个拓扑排序问题,小的数相当于安排在前面的任务
输出的第i个数就是第i个任务,那么a[1]尽可能小说明任务1要尽可能早做,b[1]尽可能小说明任务2要尽可能早做……
方法就是把DAG反向建边得到新图,在新图中求字典序最大的拓扑排序,再将这个排序反序输出就是满足要求的答案

 

IMP:

求一个字典序最小的拓扑排序,正确的做法并不是尽量把小的塞到前面,

而是把大的尽量塞到后面。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
const int N = 300500;
int point[N],to[N],next[N],cc;
int dui[N],dcc;
int ru[N];
int sc[N];
int n,m;
void AddEdge(int x,int y) {
    cc++;
    next[cc]=point[x];
    point[x]=cc;
    to[cc]=y;
    ru[y]++;
}
void Add(int x) {
    dcc++;
    int now=dcc;
    int next=now/2;
    while(next && dui[next]<x) {
        dui[now]=dui[next];
        now=next;
        next=now/2;
    }
    dui[now]=x;
}
int Del() {
    int val=dui[1];
    int now=1;
    int next=now*2;
    if(next+1<dcc && dui[next+1]>dui[next])
        next++;
    while(next<dcc && dui[next]>dui[dcc]) {
        dui[now]=dui[next];
        now=next;
        next=now*2;
        if(next+1<dcc && dui[next+1]>dui[next])
            next++;
    }
    dui[now]=dui[dcc];
    dcc--;
    return val;
}
int main() {
    int i,j;
    cin>>n>>m;
    while(m--) {
        int a,b,c;
        cin>>c>>a>>b;
        if(c==1) {
            AddEdge(a*2,b*2-1);
            AddEdge(b*2,a*2-1);
        } else
            AddEdge(b*2-1,a*2);
    }
    for(i=1; i<=n; i++)
        AddEdge(i*2,i*2-1);
    n*=2;
    for(i=1; i<=n; i++) {
        if(!ru[i])
            Add(i);
    }
    for(i=n; i>=1; i--) {
        if(!dcc) {
            printf("Wrong\n");
            return 0;
        }
        int now=Del();
        int then=point[now];
        while(then) {
            int tox=to[then];
            ru[tox]--;
            if(!ru[tox])
                Add(tox);
            then=next[then];
        }
        sc[now]=i;
    }
    for(i=1; i<=n; i++) {
        cout<<sc[i];
        if(i&1)
            cout<<' ';
        else
            cout<<endl;
    }
    return 0;
}

 

posted @ 2018-03-17 10:47  xayata  阅读(216)  评论(0编辑  收藏  举报