题目大意
A为未知的一个元素两两不相同的序列
现在给定一些区间和这个区间的最小值(不一定对)
问那个区间是最先与之前的区间冲突的
分析
一开始想写一些奇怪的线段树,然后发现自己并不会写。。。
于是就想了想如何判断几个区间是否合法,发现:
最小值相同的区间放在一起,求出他们的交集及并集,如果区间交为空说明序列中有重复数字,不合法。
如果一个最小值为a1的并集被a2的交集覆盖了,且a1<a2,则答案不合法。这个可以用并查集弄弄:
于是 i 在并查集中的根就是 i 所在的最长连续覆盖区间的右端点 +1,也就是说 后面第一个没被覆盖的位置。
覆盖 [l, r] 时就从 l 开始,每次找到下一个没被覆盖的位置,如果还没超过 r, 就把他覆盖然后合并。
ps:并查集用while,不然会暴栈,对c++深深的恶意。。。
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
int f[1500000];
struct arr{
int l,r,w;
}a[30000],b[30000];
struct arr1{
int l,r;
int L,R;
}c[30000];
int n,m;
bool cmp(arr a,arr b)
{
return a.w>b.w;
}
int find(int x)
{
int y=x;
while (f[x]!=x)
{
x=f[x];
}
int z=0;
while (f[y]!=y)
{
z=y;
y=f[y];
f[z]=x;
}
return x;
}
int check(int mid)
{
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
for (int i=1;i<=mid;i++)
b[i]=a[i];
sort(b+1,b+1+mid,cmp);
int nn=0;
for (int i=1;i<=mid;i++)
if (b[i-1].w!=b[i].w)
{
nn++;
c[nn].l=c[nn].L=b[i].l;
c[nn].r=c[nn].R=b[i].r;
}
else
{
c[nn].l=min(c[nn].l,b[i].l);
c[nn].r=max(c[nn].r,b[i].r);
c[nn].L=max(c[nn].L,b[i].l);
c[nn].R=min(c[nn].R,b[i].r);
if (c[nn].R<c[nn].L) return 1;
}
for (int i=1;i<=n+1;i++)
f[i]=i;
for (int i=1;i<=nn;i++)
{
int x=c[i].L,y=c[i].R+1;
if (find(x)==find(y))
return 1;
x=c[i].l,y=c[i].r+1;
while (find(x)<y)
{
x=f[x];
f[x]++;
x++;
}
}
return 0;
}
int main()
{
//freopen("bales.in","r",stdin);
//freopen("bales.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);
}
int l=0,r=m;
while (l<r)
{
int mid=(l+r+1)/2;
if (check(mid))
r=mid-1;
else
l=mid;
}
if (!check(m)) l=-1;
printf("%d",l+1);
}