zoukankan      html  css  js  c++  java
  • 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 '
    '
    #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
    ",res);
    
    
    }
    
  • 相关阅读:
    stm8s103 EEPROM烧程序时能否保留
    NEC芯片特别说明
    pic中断特别说明
    删除排序链表中的重复元素 II
    被围绕的区域
    计数二进制子串
    简单工厂模式
    打家劫舍 II
    打家劫舍
    相同的树
  • 原文地址:https://www.cnblogs.com/waryan/p/13492955.html
Copyright © 2011-2022 走看看