标签:poj3657 usaco 2008 jan gold haybale guessing 二分答案 并查集
题意:
输入n、m表示数列长度为n,有m条有序的限制{l,r,x}。
限制:l~r间所有数最小值为x。
问到第几条限制开始出现矛盾,都不出现输出"0"。
题解:
首先这题比较厉害,正常解有点难,不妨转化成二分答案。
我们二分“答案”,也就是第ans条出现矛盾。
考虑到若一条限制S所在区间被另一个限制Seg包含,且Seg这条限制的x又比S.x大,
那么也就是意为
① [Seg.l,Seg.r]间最小值为Seg.x
② [S .l,S .r]间最小值为S .x
③S.x < Seg.x
易得这是矛盾情况且是唯一矛盾情况,即不存在其它矛盾情况。
然后我们就可以怒check了。
这时候涉及一种想法:
我们可以 以x为关键字对当前一次check涉及的“限制”降序排序、
然后记录一个节点(或区间)是否被覆盖。
线段树显然是可以过的。 (...也显然是需要好几K的常数优化的
所以又有了一个技巧:
我们可以维护一个并查集 f[i]=j表示j+1到i这段区间都被覆盖了。
然后均摊是貌似是大常数O(n),,总之非常快就是了,我都没有离散化就高速过了。 ...(虽然它不是瓶颈
对于这个时间复杂度分析如果谁能证明是n*logn,欢迎留言打脸。
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 1001000 #define M 30000 #define inf 0x3f3f3f3f using namespace std; /*struct LSH { int x,note; bool flag; bool operator < (const LSH &a)const{return x<a.x;} }lsh[M<<1];*/ struct Lux { int l,r,x; bool operator < (const Lux &a)const{return x>a.x;} }q[M],Q[M]; int n,m,f[N]; int stk[N],top; int find(int x) { top=0; while(f[x]!=x)stk[++top]=x,x=f[x]; while(top)f[stk[top--]]=x; return x; } bool check(int mid) { int i,j,k,t; int L,R,l,r; for(i=1;i<=n;i++)f[i]=i; for(i=1;i<=mid;i++)q[i]=Q[i]; sort(q+1,q+mid+1); for(i=1;i<=mid;i=j+1) { L=l=q[i].l,R=r=q[i].r; for(j=i;j<mid&&q[j+1].x==q[j].x;) { j++; L=min(L,q[j].l),R=max(R,q[j].r); l=max(l,q[j].l),r=min(r,q[j].r); } if(find(r)<l)return 0; for(t=R;k=find(t),k>=L;t=k-1)f[k]=L-1; } return 1; } int main() { // freopen("test.in","r",stdin); int i,j,k; int l,r,mid,ans; scanf("%d%d",&n,&m); for(i=1;i<=m;i++)scanf("%d%d%d",&Q[i].l,&Q[i].r,&Q[i].x); l=1,r=m,ans=0; for(i=1;i<=20&&l<=r;i++) { mid=l+r>>1; if(check(mid))l=mid+1; else ans=mid,r=mid-1; } printf("%d\n",ans); return 0; }
【POJ3657】【USACO 2008 Jan Gold】 1.Haybale Guessing 二分答案,并查集check
标签:poj3657 usaco 2008 jan gold haybale guessing 二分答案 并查集
原文地址:http://blog.csdn.net/vmurder/article/details/42105647