kb-07线段树-12--二分查找区间边界

  1 /*
  2    hdu4614
  3    本题刚开始想能不能记录该区间最前面开始的点,最后面的点,区间空的数量;但是病不行
  4    然后线段树的本质是区间操作,所以!这题主要就是区间的空的全放满,只要定出区间的边界就好办了;
  5    这里用二分查找的方法,现计算满足数量的区间的尾,因为头已经确定了,及时不放花也是确定的,只要靠数量定出尾就可以了;
  6    然后就是区间修改了;
  7  */
  8 #include<iostream>
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<algorithm>
 12 #define MAX_N 50001
 13 using namespace std;
 14 int n,m,first,last,num,x;
 15 struct tree
 16 {
 17     int l,r,fir,las,s,same,val;
 18 }tr[MAX_N*4];
 19 void build(int rt,int l,int r)
 20 {
 21     tr[rt].l=l;tr[rt].r=r;
 22     tr[rt].fir=l;
 23     tr[rt].las=r;
 24     tr[rt].s=0;
 25     tr[rt].val=r-l+1;
 26     if(l==r)
 27     {
 28         tr[rt].same=0;
 29         return ;
 30     }
 31     tr[rt].same=1;
 32     int mid=(l+r)/2;
 33     build(rt<<1,l,mid);
 34     build(rt<<1|1,mid+1,r);
 35 }
 36 void Pushup(int rt)
 37 {
 38     int l=rt<<1,r=rt<<1|1;
 39     if(tr[l].fir==0)
 40         tr[rt].fir=tr[r].fir;
 41     else tr[rt].fir=tr[l].fir;
 42     if(tr[r].las==0)
 43         tr[rt].las=tr[l].las;
 44     else tr[rt].las=tr[r].las;
 45     tr[rt].val=tr[r].val+tr[l].val;
 46 
 47 }
 48 void Pushdown(int rt)
 49 {
 50     if(tr[rt].l==tr[rt].r)
 51         return ;
 52     int l=rt<<1,r=rt<<1|1;
 53     if(tr[rt].same)
 54     {
 55         if(tr[rt].s==1)
 56         {
 57             tr[r].val=tr[l].val=0;
 58             tr[r].s=tr[l].s=1;
 59             tr[r].fir=tr[l].fir=0;
 60             tr[r].las=tr[l].las=0;
 61             tr[r].same=tr[l].same=1;
 62             tr[rt].same=0;
 63         }
 64         else
 65         {
 66             tr[r].val=tr[r].r-tr[r].l+1;
 67             tr[l].val=tr[l].r-tr[l].l+1;
 68             tr[r].s=tr[l].s=0;
 69             tr[r].same=tr[l].same=1;
 70             tr[r].fir=tr[r].l;
 71             tr[r].las=tr[r].r;
 72             tr[l].fir=tr[l].l;
 73             tr[l].las=tr[l].r;
 74             tr[rt].same=0;
 75         }
 76     }
 77 }
 78 void Update1(int rt,int l,int r)
 79 {
 80     if(x<=0)
 81         return ;
 82     if(tr[rt].val==0)
 83         return ;//在二分查找定区间后,少了这一句所以一直tle
 84     if(tr[rt].l==l&&tr[rt].val>0)
 85     {
 86         if(first==0)
 87             first=tr[rt].fir;
 88         if(tr[rt].val<=x)
 89         {
 90             if(last<tr[rt].las)
 91                 last=tr[rt].las;
 92             x-=tr[rt].val;
 93             tr[rt].same=1;
 94             tr[rt].s=1;
 95             tr[rt].val=0;
 96             tr[rt].fir=0;
 97             tr[rt].las=0;
 98             return ;
 99         }
100     }
101     if(tr[rt].l==tr[rt].r)
102         return ;
103     Pushdown(rt);
104     int L=rt<<1,R=rt<<1|1;
105     if(l<=tr[L].r)
106     {
107         if(r<=tr[L].r)
108             Update1(L,l,r);
109         else
110             Update1(L,l,tr[L].r);
111     }
112     if(r>=tr[R].l)
113     {
114         if(l>=tr[R].l)
115             Update1(R,l,r);
116         else
117             Update1(R,tr[R].l,r);
118     }
119     Pushup(rt);
120 }
121 void Update2(int rt,int l,int r)
122 {
123     if(tr[rt].l==l&&tr[rt].r==r)
124     {
125         num+=r-l+1-tr[rt].val;
126         tr[rt].val=r-l+1;
127         tr[rt].s=0;
128         tr[rt].same=1;
129         tr[rt].fir=l;
130         tr[rt].las=r;
131         return;
132     }
133     if(tr[rt].l==tr[rt].r)
134         return ;
135     Pushdown(rt);
136     int L=rt<<1,R=rt<<1|1;
137     if(l<=tr[L].r)
138     {
139         if(r<=tr[L].r)
140             Update2(L,l,r);
141         else
142             Update2(L,l,tr[L].r);
143     }
144     if(r>=tr[R].l)
145     {
146         if(l>=tr[R].l)
147             Update2(R,l,r);
148         else
149             Update2(R,tr[R].l,r);
150     }
151     Pushup(rt);
152 }
153 int sum(int rt,int l,int r)
154 {
155     if(tr[rt].l==l&&tr[rt].r==r)
156     {
157         return tr[rt].val;
158     }
159     int ans=0;
160     Pushdown(rt);//因为只是查询,所以区间整体并没有变,就没有必要pushup了;
161     int L=rt<<1,R=rt<<1|1;
162     if(l<=tr[L].r)
163     {
164         if(r<=tr[L].r)
165             ans+= sum(L,l,r);
166         else
167             ans+= sum(L,l,tr[L].r);
168     }
169     if(r>=tr[R].l)
170     {
171         if(l>=tr[R].l)
172             ans+= sum(R,l,r);
173         else
174             ans+= sum(R,tr[R].l,r);
175     }
176     return ans;
177 }
178 int bisearch(int a,int f)
179 {
180     if(sum(1,a,n)==0)
181         return -1;
182     if(sum(1,a,n)<f)//此处的等于号的问题;
183         return n;
184     int l=a,r=n;
185     int ans=a;
186     while(l<=r)
187     {
188         int mid=(l+r)/2;
189         if(sum(1,a,mid)>=f)//以及此处的等于号;
190         {
191             ans=mid;//这里ans的取值;
192             r=mid-1;
193         }
194         else l=mid+1;
195     }
196     return ans;
197 }
198 int main()
199 {
200     int T;
201     scanf("%d",&T);
202     while(T--)
203     {
204         scanf("%d%d",&n,&m);
205         build(1,1,n);
206         for(int i=0;i<m;i++)
207         {
208             int ty,z,y;
209             scanf("%d%d%d",&ty,&z,&y);
210             if(ty==1)
211             {
212                 int t=bisearch(z+1,y);
213                 if(t!=-1)
214                 {
215                     x=y;
216                     first=0;
217                     last=0;
218                     Update1(1,z+1,t);
219                     printf("%d %d
",first-1,last-1);
220                 }
221                 else 
222                     printf("Can not put any one.
");
223             }
224             else 
225             {
226                 num=0;
227                 Update2(1,z+1,y+1);
228                 printf("%d
",num);
229             }
230         }
231         printf("
");
232     }
233     return 0;
234 }
原文地址:https://www.cnblogs.com/by-1075324834/p/4543002.html