NC19858战争(war)
战争(war)
https://ac.nowcoder.com/acm/problem/19858
题意
如果后面的人和前面的人矛盾那么后面的人一定说谎了,输出他的位置。否则如果没有说谎输出
思路
二分长度,因为如果二分的区间[l,mid]有人说谎那么[r,mid]就不用判断了。但是如果[l,mid]没有人说谎,那么我们就要将mid扩大继续寻找说谎的人。仔细想想就是二分。在某个位置前面是没有说谎的,但是后面一定就会有说话的,二分这个位置。
check函数
我们先将结构体按从大到小排序,然后我们枚举每一种情况。
- 在枚举情况时
是小于
的,如果
在区间
里面,那么这种情况是不行的。(根据
判断)
- 如果一系列
相等,那么如果其中有两两不相交的区间,那么这种情况是不行的。(因为城市兵力两两不同)
或者
都可以判断这种情况,可以舍去
)
为什么呢?因为我取了
的
,和
取了
。如果有不相交的区间那么这两个是
的。
- 更新所有这个最大范围内的节点的父节点,将其父亲设为左端点的前一个。当
时,我们可以跳过一段范围,因为这段范围是可以存在的。
简单描述
我们只要排除每种不可能的情况就可以了。
首先不可能的是,相等但区间有两两不相交的
其次是,在某一段区间里有更小的区间(此时的前者是大于后者
的,按排序后的情况枚举)
比如说最小值是
,
最小值是
,这种情况是不可能的(
判断)。
#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); }