• [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
    ");
                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;
    }
  • 相关阅读:
    Nginx 对访问量的控制
    Shell入门
    小程序如何处理键盘覆盖输入框
    移动端适配之二:visual viewport、layout viewport和ideal viewport介绍
    javascript-对象
    bind函数作用、应用场景以及模拟实现
    「面试题」如何实现一个圣杯布局?
    一款轮播组件的诞生
    超火js库: Lodash API例子
    js 中的 number 为何很怪异
  • 原文地址:https://www.cnblogs.com/shandongs1/p/8588148.html
Copyright © 2020-2023  润新知