zoukankan      html  css  js  c++  java
  • 100: cf 878C set+并查集+链表

    $des$
    Berland要举行 $n$ 次锦标赛,第一次只有一个人,之后每一次会新
    加入一个人。锦标赛中有 $k$ 种运动项目,每个人在这 $k$ 种项目上都有一
    个能力值,每次会选择任意两个还未被淘汰的人进行某个项目的比
    赛,能力值高的人胜出,输的人被淘汰,直至只剩下一个人成为冠
    军。
    给出每个人每个项目的能力值,保证它们两两不同,求每次锦标
    赛有多少人可能成为冠军。

    $sol$
    只要选手 $a$ 在某个项目上比选手 $b$ 强, $a$ 就可以淘汰 $b$,我们可以连
    一条 $a$ 到 $b$ 的边。
    对整个图求强连通分量,缩点后一定会形成一个竞赛图,拓扑序
    最靠前的分量中的所有点都可能成为冠军。
    每加入一个点时,我们可能需要合并拓扑序在一段区间内强连通
    分量。用set按拓扑序维护每个强连通分量,对每个分量记录它的大
    小,以及在每个项目上的最大和最小能力值,就可以直接在set上二分
    找到需要合并的区间。
    最多只会合并 $n - 1$ 次,时间复杂度 $O(nklogn)$

    $code$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define gc getchar()
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    #define Rep(i, a, b) for(int i = a; i <= b; i ++)
    #define MP(a, b) make_pair(a, b)
    
    const int N = 5e4 + 10;
    
    int A[N][15];
    int Max[N][15];
    int n, m;
    int fa[N], size[N], nxt[N], last = 1;
    int Answer[N];
    
    set<pair<int, int> > S[15];
    
    int Get(int x) {
        return fa[x] == x ? x : fa[x] = Get(fa[x]);
    }
    
    void Merge(int a, int b) {
        Rep(i, 1, m) Max[b][i] = max(Max[b][i], Max[a][i]);
        size[b] += size[a], fa[a] = b;
    }
    
    int main() {
        n = read(), m = read();
        
        Rep(i, 1, n) Rep(j, 1, m) Max[i][j] = A[i][j] = read();
        Rep(i, 1, n) fa[i] = i, size[i] = 1;
        Rep(i, 1, m) S[i].insert(MP(A[1][i], 1));
        
        Answer[1] = 1;
        
        Rep(i, 2, n) {
            int a = 0, b = 0;
            set<pair<int, int> > :: iterator it;
            Rep(j, 1, m) {
                it = S[j].upper_bound(MP(A[i][j], i));
                if(it != S[j].end()) {
                    int t = Get((*it).second);
                    if(!b || Max[t][j] < Max[b][j]) b = t;
                }
                if(it != S[j].begin()) {
                    it --;
                    int t = Get((*it).second);
                    if(!a || Max[t][j] > Max[a][j]) a = t;
                }
                S[j].insert(MP(A[i][j], i));
            }
            if(!a) nxt[i] = b;
            else if(!b) last = i, nxt[a] = i;
            else if(a == b) Merge(i, a);
            else if(Max[a][1] < Max[b][1]) nxt[a] = i, nxt[i] = b;
            else {
                for(int t = b; t != a; t = nxt[t], Merge(t, b));
                Merge(i, b);
                nxt[b] = nxt[a];
                if(a == last) last = b;
            }
            Answer[i] = size[last];
        }
        
        Rep(i, 1, n) cout << Answer[i] << "
    ";
        
        return 0;
    }
  • 相关阅读:
    《程序猿闭门造车》之NBPM工作流引擎
    CryptographicException异常处理方法
    nodejs简单模仿web.net web api
    Windows Mobile设备操作演示准备工作小记
    PPT定时器小记
    winDBG排错小记
    Ubuntu 16.04应用布署小记
    Ubuntu 16.04环境布署小记
    Ubuntu 16.04系统布署小记
    Dokuwiki布署小记
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9791600.html
Copyright © 2011-2022 走看看