询问

3 篇文章 0 订阅
1 篇文章 0 订阅

Description

有一个长度为  n    n   的正整数序列,序列中元素两两不同且都在 [1109] [ 1 , 10 9 ] 中。
你不知道这个序列是什么。
现在有  Q    Q   个询问 lr l , r ,每次询问序列中区间 [l,r] [ l , r ] 的最小值,有一个人回答了这  Q    Q   个问题。
但是他太不靠谱,回答可能会自相矛盾。
于是我们要求出一个最小的  p    p   ,回答的  p    p   个询问后出现了答案自相矛盾的情况。
如果所有的  Q    Q   个答案是不互相矛盾的,就输出 0 0

Input

第一行两个整数 nQ
接下来  Q    Q   行,第  i    i   行三个整数  liriansi   l i , r i , a n s i ,表示第  i    i   个询问 [liri] [ l i , r i ] ,回答的答案为  ansi   a n s i

output

按照题目要求输出一行一个整数。

Sample Input

20 4
1 10 7
5 19 7
3 12 8
11 15 12

Sample Output

3

Data Constraint

 n106,m25000,1ansi109   n ≤ 10 6 , m ≤ 25000 , 1 ≤ a n s i ≤ 10 9

Solution

考虑二分答案,接下来判断前mid个询问是否矛盾。
把所有询问按照答案从大到小排序,把答案相同的那些询问放在一起,求出区
间交及区间并,如果区间交为空说明序列中有重复数字,直接无解;否则我们看
看区间交是否全被覆盖,如果全被覆盖显然之前的区间答案错误产生矛盾,如
果没全被覆盖我们就把区间并(由于区间交不为空区间并显然是一段连续区间)
进行覆盖。
正确性在于如果有 l1l2r2l1 l 1 ≤ l 2 ≤ r 2 ≤ l 1 ,那么显然有 ans2ans1 a n s 2 ≥ a n s 1 ,而如果答案小
的区间全被覆盖就相当于 ans2<ans1 a n s 2 < a n s 1 。这就产生了矛盾。
那么我们可以用线段树或并查集的做法,下面就讲讲并查集。
如果我们将要覆盖 [lr] [ l , r ] ,那么我们就要使l~r合并到r+1去,所以当 faii f a i ≠ i
时就说明该区域已被覆盖,并且当  fai=faj    f a i = f a j   时说明i,j被同一区域覆盖。易得最多只合并  n    n   次。

Code

var     l,r,mid,fax,fay,i,n,t:longint;
        g,f:array[1..2] of longint;
        a,b:array[0..30000,1..3] of longint;
        fa:array[1..1000005] of longint;
function get(x:longint):longint;
begin
    if fa[x]=x then exit(x);
    fa[x]:=get(fa[x]);exit(fa[x]);
end;
procedure qsort(x,y:longint);
var     i,j:longint;
        k:int64;
begin
    i:=x;
    j:=y;
    k:=b[(i+j) div 2,3];
    repeat
        while b[i,3]>k do inc(i);
        while b[j,3]<k do dec(j);
        if i<=j then begin
            b[0]:=b[i];
            b[i]:=b[j];
            b[j]:=b[0];
            inc(i);dec(j);
        end;
    until   i>j;
    if i<y then qsort(i,y);
    if j>x then qsort(x,j);
end;
function min(x,y:longint):longint;
begin if x<y then exit(x);exit(y);end;
function max(x,y:longint):longint;
begin if x>y then exit(x);exit(y);end;
function pan(x:longint):boolean;
begin
    for i:=1 to x do b[i]:=a[i];
    for i:=1 to n+1 do fa[i]:=i;
    qsort(1,x);
    f[1]:=b[1,1];f[2]:=b[1,2];
    g[1]:=b[1,1];g[2]:=b[1,2];
    b[x+1,3]:=-1;
    for i:=2 to x+1 do begin
        if b[i,3]=b[i-1,3] then begin
            if (b[i,1]>f[2]) or (b[i,2]<f[1]) then exit(false) else
            f[1]:=max(f[1],b[i,1]);
            f[2]:=min(f[2],b[i,2]);
            g[1]:=min(g[1],b[i,1]);
            g[2]:=max(g[2],b[i,2]);
            continue;
        end else begin
            fax:=get(f[1]);
            fay:=get(f[2]+1);
            if fax=fay then exit(false);
            fax:=get(g[1]);
            fay:=get(g[2]+1);
            while fax<>fay do begin
                fa[fax]:=fax+1;
                fax:=get(fax+1);
            end;
            f[1]:=b[i,1];f[2]:=b[i,2];
            g[1]:=b[i,1];g[2]:=b[i,2];
        end;
    end;
        exit(true);
end;
begin
assign(input,'bales.in');reset(input);
assign(output,'bales.out');rewrite(output);
        readln(n,t);
        for i:=1 to t do
        readln(a[i,1],a[i,2],a[i,3]);
        l:=1;r:=t;
    while l<r do begin
        mid:=(l+r) div 2;
        if pan(mid) then l:=mid+1 else r:=mid;
    end;
    if (l=t) and (pan(l)) then writeln(0) else writeln(l);
close(input);
close(output);
end.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值