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);
}