【bzoj1594-猜数游戏】线段树

题解:

矛盾只有两种情况:

一.先前确定了x在区间(l,r),但是现在发现x在区间(l1,r1),并且两个区间不相交。

二.一个区间的最小值是x,这个区间中有一个子区间的最小值比x更小。

 

首先可以明确,对于每个x,我们可以不断地缩小x的范围(取区间的交集)。

那就先处理第一种矛盾,假设第一种矛盾第一次出现是在信息i。

那么我们就在信息1~i中寻找是否有第二种矛盾(此时保证了1~i中不会有第一种矛盾)。

 

 

每个信息有l,r,d三个值,我们按照d排序。那就在扫到下面那个区间的时候,我们一定已经有了上面的区间。

然后我们在线段树里面看红色的这个区间是否已经被完整地覆盖了。

线段树每个节点维护覆盖这个节点的最前面一个信息(因为题目要求最前的信息)。

如果红色区间被多个区间加在一起完整覆盖,那我们要去这多个区间的信息的max值(必须等到它也出现了才能完整覆盖)

最后维护一下ans。

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<ctime>
  6 #include<queue>
  7 #include<algorithm>
  8 using namespace std;
  9 
 10 const int N=1000010,INF=(int)1e9;
 11 struct node{int l,r,lc,rc,id,lazy;}t[2*N];
 12 struct nod{int d,id;}p[N];
 13 struct nd{int l,r,d,id;}q[N];
 14 int n,m,tl,L[N],R[N];
 15 
 16 bool cmp_nod(nod x,nod y){return x.d<y.d;}
 17 bool cmp_nd(nd x,nd y)
 18 {
 19     if(x.d!=y.d) return x.d>y.d;
 20     return x.id<y.id;
 21 }
 22 int minn(int x,int y){return x<y ? x:y;}
 23 int maxx(int x,int y){return x>y ? x:y;}
 24 
 25 int buildtree(int l,int r)
 26 {
 27     int x=++tl;
 28     t[x].l=l;t[x].r=r;
 29     t[x].lc=t[x].rc=0;
 30     t[x].id=INF;t[x].lazy=INF;
 31     if(l<r)
 32     {
 33         int mid=(l+r)/2;
 34         t[x].lc=buildtree(l,mid);
 35         t[x].rc=buildtree(mid+1,r);
 36     }
 37     return x;
 38 }
 39 
 40 void upd(int x)
 41 {
 42     if(t[x].lazy==INF) return ;
 43     int id=t[x].lazy,lc=t[x].lc,rc=t[x].rc;
 44     t[x].lazy=INF;
 45     t[x].id=minn(t[x].id,id);
 46     if(lc) t[lc].lazy=minn(t[lc].lazy,id);
 47     if(rc) t[rc].lazy=minn(t[rc].lazy,id);
 48 }
 49 
 50 void change(int x,int l,int r,int id)
 51 {
 52     upd(x);
 53     if(t[x].l==l && t[x].r==r) 
 54     {
 55         t[x].lazy=minn(t[x].lazy,id);
 56         upd(x);
 57         return ;
 58     }
 59     int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/2;
 60     if(r<=mid) change(lc,l,r,id);
 61     else if(l>mid) change(rc,l,r,id);
 62     else 
 63     {
 64         change(lc,l,mid,id);
 65         change(rc,mid+1,r,id);
 66     }
 67     int now=maxx(t[lc].id,t[rc].id);
 68     if(now<INF) t[x].id=now;//debug 一个小区间都被覆盖了,大区间也会被覆盖。
 69 }
 70 
 71 int query(int x,int l,int r)
 72 {
 73     upd(x);
 74     if(t[x].l==l && t[x].r==r) return t[x].id;
 75     int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/2;
 76     if(r<=mid) return query(lc,l,r);
 77     else if(l>mid) return query(rc,l,r);
 78     else return maxx(query(lc,l,mid),query(rc,mid+1,r));
 79 }
 80 
 81 
 82 int main()
 83 {
 84     // freopen("a.in","r",stdin);
 85     freopen("bales.in","r",stdin);
 86     freopen("bales.out","w",stdout);
 87     scanf("%d%d",&n,&m);
 88     tl=0;
 89     for(int i=1;i<=m;i++)
 90     {
 91         scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].d);
 92         q[i].id=i;
 93         p[i].d=q[i].d;p[i].id=i;
 94     }
 95     sort(p+1,p+1+m,cmp_nod);
 96     int mx=0;p[0].d=0;
 97     for(int i=1;i<=m;i++) 
 98     {
 99         if(p[i].d!=p[i-1].d) mx++;
100         q[p[i].id].d=mx;
101     }
102     for(int i=1;i<=mx;i++) L[i]=1,R[i]=n;
103     int ans=INF;
104     for(int i=1;i<=m;i++)
105     {
106         int x=q[i].d;
107         if(q[i].l>R[x] || q[i].r<L[x]) {ans=i;m=i-1;break;}
108         L[x]=maxx(L[x],q[i].l);
109         R[x]=minn(R[x],q[i].r);
110     }
111     // printf("%d
",ans);
112     buildtree(1,n);
113     sort(q+1,q+1+m,cmp_nd);
114     for(int i=1;i<=mx;i++) L[i]=1,R[i]=n;
115     int x,now,j=1;
116     for(int i=1;i<=m;i++)
117     {
118         while(j<i && q[j].d!=q[i].d) 
119         {
120             change(1,q[j].l,q[j].r,q[j].id);
121             j++;
122         }
123         x=q[i].d;
124         L[x]=maxx(L[x],q[i].l);
125         R[x]=minn(R[x],q[i].r);
126         now=query(1,L[x],R[x]);
127         ans=minn(ans,maxx(q[i].id,now));
128     }
129     if(ans<INF) printf("%d
",ans);
130     else printf("0
");
131     return 0;
132 }

 

原文地址:https://www.cnblogs.com/KonjakJuruo/p/6016553.html