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;
}
原文地址:https://www.cnblogs.com/shandongs1/p/9791600.html