zoukankan      html  css  js  c++  java
  • gym100801I Insider's Information

    题意

    要求构造大小为 (n) 的排列,要求至少 (lceil frac{m}{2} ceil) 条限制:第 (i) 条限制 ((a_i,b_i,c_i)) 形如排列中 (b_i) 的位置要在 (a_i)(c_i) 之间。

    题解

    神仙题。

    这个题一般确定排列的方法都不能用了,我们考虑这个在两个数中间的限制:考虑用按照顺序每次将一个数放到前面或者后面的方式。

    因为保证有解,所以肯定能搞出来一个答案,也就肯定有一种放置顺序。我们假设我们知道了放置顺序,考虑如何去构造出答案,分类讨论一下:

    假设一个限制中第一个被放入的数是 (a_i),那么如果下一个数是 (b_i),就要和 (a_i) 放在同侧,否则就要放在不同侧。

    所以我们加入一个点的时候,算出它放在左边和右边分别能满足多少限制,选择最大的那个即可。这样相当于将所有限制分成若干组,每一组至少取了一半,所以满足题目限制。

    现在问题在于如何找到这个放置顺序:发现如果在三元组内是 (b_i) 先出现,那么怎么放置都不满足条件,所以我们要求出的序列形如要求 (a_i)(c_i) 出现在 (b_i) 之前,用类似拓扑排序的方法即可。

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 2e5 + 5;
    int n,m,a[MAXN],b[MAXN],c[MAXN];
    std::vector<int> G[MAXN],lim[MAXN];
    int deg[MAXN];
    int dfn[MAXN],p[MAXN];
    bool zt[MAXN];// left=0 right=1
    bool vis[MAXN];
    
    int main(){
    #ifndef RainAir
        freopen("insider.in","r",stdin);
        freopen("insider.out","w",stdout);
    #endif
        scanf("%d%d",&n,&m);
        FOR(i,1,m){
            scanf("%d%d%d",a+i,b+i,c+i);
            G[a[i]].pb(i);
            G[c[i]].pb(i);
            ++deg[b[i]];
        }
        std::queue<int> q;int ts = 0;
        FOR(i,1,n) if(!deg[i]) q.push(i);
        while(!q.empty()){
            int v = q.front();q.pop();
            dfn[v] = ++ts;
            for(auto x:G[v]){
                if(vis[x]) continue;
                vis[x] = 1;
                if(!--deg[b[x]]){
                    q.push(b[x]);
                }
            }
        }
        FOR(i,1,m) assert(!(dfn[b[i]] < dfn[a[i]] && dfn[b[i]] < dfn[c[i]]));
        FOR(i,1,n) p[dfn[i]] = i;
        FOR(i,1,m) if(dfn[a[i]] > dfn[c[i]]) std::swap(a[i],c[i]);
        FOR(i,1,m) lim[b[i]].pb(i),lim[c[i]].pb(i);
        FOR(i,1,n){
            int cnt[2];CLR(cnt,0);
            int v = p[i];
            for(auto x:lim[v]){
                if(v == b[x]){
                    if(dfn[c[x]] < dfn[b[x]]) continue;
                    cnt[zt[a[x]]]++;
                }
                if(v == c[x]){
                    if(dfn[b[x]] < dfn[c[x]]) continue;
                    cnt[zt[a[x]]^1]++;
                }
            }
            zt[v] = cnt[0] > cnt[1] ? 0 : 1;
        }
        std::vector<int> v1,v2;
        FOR(i,1,n){
            if(zt[p[i]]) v2.pb(p[i]);
            else v1.pb(p[i]);
        }
        std::reverse(all(v2));
        for(auto x:v1) printf("%d ",x);
        for(auto x:v2) printf("%d ",x);
        puts("");
        return 0;
    }
    
  • 相关阅读:
    Win32C++调用C#(一):开篇
    C#+ICE+TCP通信=数据传输
    第一章 程序设计和C语言
    第一章 HTML5,CSS3及响应式设计入门恢复
    第一章 程序设计和C语言
    HTTP状态码
    HTML 实践
    HTML基础
    创建HTML文件与建立HTML格式
    HTML标签
  • 原文地址:https://www.cnblogs.com/rainair/p/14304956.html
Copyright © 2011-2022 走看看