【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\n",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\n",ans);
130 else printf("0\n");
131 return 0;
132 }