NC19858战争(war)(并查集+二分)

NC19858战争(war)

题意

如果后面的人和前面的人矛盾那么后面的人一定说谎了,输出他的位置。否则如果没有说谎输出\(K+1\)

思路

二分长度,因为如果二分的区间[l,mid]有人说谎那么[r,mid]就不用判断了。但是如果[l,mid]没有人说谎,那么我们就要将mid扩大继续寻找说谎的人。仔细想想就是二分。在某个位置前面是没有说谎的,但是后面一定就会有说话的,二分这个位置。

check函数

我们先将结构体按\(num\)从大到小排序,然后我们枚举每一种情况。

  • 在枚举情况时\(num_j\)是小于\(num_i\)的,如果\(num_j\)在区间\(num_i\)里面,那么这种情况是不行的。(根据\(l>Find(r)\)判断)
  • 如果一系列\(num\)相等,那么如果其中有两两不相交的区间,那么这种情况是不行的。(因为城市兵力两两不同)\((l>r\)或者\(l>Find(r)\)都可以判断这种情况,可以舍去\(l>r\))

为什么呢?因为我取了\(l\)\(max\),和\(r\)取了\(min\)。如果有不相交的区间那么这两个是\(l>r\)的。

  • 更新所有这个最大范围内的节点的父节点,将其父亲设为左端点的前一个。当\(fa[R]!=R\)时,我们可以跳过一段范围,因为这段范围是可以存在的。

简单描述

我们只要排除每种不可能的情况就可以了。

首先不可能的是,\(num\)相等但区间有两两不相交的

其次是,在某一段区间里有更小的区间(此时的前者\(num\)是大于后者\(num\)的,按排序后的情况枚举)

比如说\([1-16]\)最小值是\(20\)\([5-10]\)最小值是\(15\),这种情况是不可能的(\(l>Find(r)\)判断)。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define DOF 0x7f7f7f7f
#define endl '\n'
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(case, x) cout << case << "  : " << x << endl
#define open freopen("ii.txt", "r", stdin)
#define close freopen("oo.txt", "w", stdout)
#define IO                       \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0)
#define pb push_back
using namespace std;
//#define int long long
#define lson rt << 1
#define rson rt << 1 | 1
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<long long, long long> PII;
const int maxn = 1e6 + 10;
inline int read() {
    char ch = getchar();
    int f = 1;
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            f = -f;
        ch = getchar();
    }
    int x = 0;
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

struct node {
    int l,r,num;
    bool operator <(const node x)const {
        return num>x.num;
    }

} node[maxn],t[maxn];
int n,m;
int fa[maxn];
int Find(int x) {
    return x==fa[x]?x:fa[x]=Find(fa[x]);
}


bool check(int k) {
    for(int i=1; i<=k; ++i)t[i]=node[i];
    sort(t+1,t+1+k);
    for(int i=1; i<=n; ++i) {
        fa[i]=i;
    }
    for(int i=1; i<=k;) {
        int j=i+1,l=t[i].l,r=t[i].r,L=t[i].l,R=t[i].r;
        while(j<=k&&t[j].num==t[i].num) {
            l=max(l,t[j].l);
            r=min(r,t[j].r);
            L=min(L,t[j].l);
            R=max(R,t[j].r);
            ++j;
        }
        if(l>r||l>Find(r)) return true;
        while(L<=R) {
            if(fa[R]==R)fa[R]=Find(L-1),--R;
            else R=Find(R);
        }
        i=j;
    }
    return false;
}

int main() {
    n=read(),m=read();
    for(int i=1; i<=m; ++i)
        node[i].l=read(),node[i].r=read(),node[i].num=read();
    int l=0,r=m+1,mid,res=m+1;
    while(l<=r) {
        mid=l+r>>1;
        if(check(mid))r=mid-1,res=mid;
        else l=mid+1;
    }
    printf("%d\n",res);


}
posted @ 2020-08-12 21:01  waryan  阅读(130)  评论(0编辑  收藏  举报