[题解]CodeForces878C Tournament

Posted scl123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解]CodeForces878C Tournament相关的知识,希望对你有一定的参考价值。

传呀传送门

啊哈——想了好久都没有想出来,幼小

题目描述

(n)个人参加一个有(k)项活动的比赛,第(i)个人完成第(j)项活动的能力为(a[i][j])

每一次选两个人,随机指定一项活动,能力强的人胜出并留下,另一人淘汰,最后留下的人获胜

问对于每一个(ileq n),前(i)个人中有几个人可能获胜

((1leq n leq 5*10^4,1leq k leq 10,1leq a[i][j]leq 10^9),保证(a)互不相同)

分析

把人看成点,对于(u,v),如果(u)可以打败(v),从(u)(v)连边。

显然,一个人可以赢当且仅当可以以它为根拎出一棵有向树。

考虑怎么维护:

可以发现,环上的每一个点的地位是相同的,所以可以先把环缩掉,然后把剩下的联通块扯成一条链,再把其他边删掉——像这样。(u)可以到达(v)当且仅当(u)可以打败(v)

技术图片

那么我们要求的,就是入度为0的联通块的大小

而且,我们发现这些联通块有一个有趣的性质就是,按照拓扑序,每一项活动的最大能力值和最小能力值都是单调的。即,记(mx/mn[x][i])(x)所在的联通块里,所有点中第(i)项活动的最大/小能力值,那么对于(u)可以走到(v),(forall i,mn[u][i]>mn[v][i],mx[u][i]>mx[v][i])

那么我们就可以用set维护每一个联通块。

再考虑加入新的点,可能会产生新的环,像下面的图一样 。那么我们只需要通过lower_bound找到粉红色的点(第一个可以打败新增点的点),然后一直往后走合并就可以啦

技术图片

代码

好像并不是特别长,然而写了好久。

set真骚气神奇啊,还有lower_bound

#include<bits/stdc++.h>
#define rep(X,A,B) for(int X=A;X<=B;X++)
#define tep(X,A,B) for(int X=A;X>=B;X--)
#define LL long long
const int N=50010;
using namespace std;

int n,m;
//---
struct nn{
    int mn[11],mx[11],sz,pd;
};

nn g[N];
//---
int WIN(nn A,nn B){
    rep(i,1,m)if(A.mx[i]>B.mn[i])return 1;
    return 0;
}
//
struct node{
    int val;
    
    bool operator <(const node &A)const {
        int x=val,y=A.val;
        if(g[y].pd==0)return !WIN(g[x],g[y]);
        return WIN(g[y],g[x]);
    }
};

set<node>mp;
set<node>::iterator pos,del;
//---
nn MERGE(nn A,nn B){
    nn res;
    res.pd=A.pd;
    res.sz=A.sz+B.sz;
    rep(i,1,m){
        res.mn[i]=min(A.mn[i],B.mn[i]);
        res.mx[i]=max(A.mx[i],B.mx[i]);
    }
    return res;
}

void SOLVE(int id){
    int x;
    g[id].sz=1;g[id].pd=0;
    rep(i,1,m){
        scanf("%d",&x);
        g[id].mn[i]=g[id].mx[i]=x;
    }
    pos=mp.lower_bound((node){id});
    while(pos!=mp.end()){
        int now=(*pos).val;
        if(WIN(g[id],g[now])&&WIN(g[now],g[id])){
            g[id]=MERGE(g[id],g[now]);
            del=pos;pos++;
            mp.erase(del);
        }
        else break;
    }
    g[id].pd=1;
    mp.insert((node){id});
    int now=(*mp.rbegin()).val;
    printf("%d
",g[now].sz);
}

int main(){
    scanf("%d%d",&n,&m);
    rep(i,1,n)SOLVE(i);
    return 0;
}

以上是关于[题解]CodeForces878C Tournament的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Educational Codeforces Round 54 题解

Codeforces 7E - Defining Macros 题解

Codeforces Round #815 (Div. 2) 题解

codeforces比赛后怎么看题解和答案

Codeforces Round #738 (Div. 2) 题解

Codeforces Round #608 (Div. 2) 题解