您的位置:首页 > 其它

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

2015-05-31 23:46 344 查看
/*
hdu4614
本题刚开始想能不能记录该区间最前面开始的点,最后面的点,区间空的数量;但是病不行
然后线段树的本质是区间操作,所以!这题主要就是区间的空的全放满,只要定出区间的边界就好办了;
这里用二分查找的方法,现计算满足数量的区间的尾,因为头已经确定了,及时不放花也是确定的,只要靠数量定出尾就可以了;
然后就是区间修改了;
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAX_N 50001
using namespace std;
int n,m,first,last,num,x;
struct tree
{
int l,r,fir,las,s,same,val;
}tr[MAX_N*4];
void build(int rt,int l,int r)
{
tr[rt].l=l;tr[rt].r=r;
tr[rt].fir=l;
tr[rt].las=r;
tr[rt].s=0;
tr[rt].val=r-l+1;
if(l==r)
{
tr[rt].same=0;
return ;
}
tr[rt].same=1;
int mid=(l+r)/2;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
}
void Pushup(int rt)
{
int l=rt<<1,r=rt<<1|1;
if(tr[l].fir==0)
tr[rt].fir=tr[r].fir;
else tr[rt].fir=tr[l].fir;
if(tr[r].las==0)
tr[rt].las=tr[l].las;
else tr[rt].las=tr[r].las;
tr[rt].val=tr[r].val+tr[l].val;

}
void Pushdown(int rt)
{
if(tr[rt].l==tr[rt].r)
return ;
int l=rt<<1,r=rt<<1|1;
if(tr[rt].same)
{
if(tr[rt].s==1)
{
tr[r].val=tr[l].val=0;
tr[r].s=tr[l].s=1;
tr[r].fir=tr[l].fir=0;
tr[r].las=tr[l].las=0;
tr[r].same=tr[l].same=1;
tr[rt].same=0;
}
else
{
tr[r].val=tr[r].r-tr[r].l+1;
tr[l].val=tr[l].r-tr[l].l+1;
tr[r].s=tr[l].s=0;
tr[r].same=tr[l].same=1;
tr[r].fir=tr[r].l;
tr[r].las=tr[r].r;
tr[l].fir=tr[l].l;
tr[l].las=tr[l].r;
tr[rt].same=0;
}
}
}
void Update1(int rt,int l,int r)
{
if(x<=0)
return ;
if(tr[rt].val==0)
return ;//在二分查找定区间后,少了这一句所以一直tle
if(tr[rt].l==l&&tr[rt].val>0)
{
if(first==0)
first=tr[rt].fir;
if(tr[rt].val<=x)
{
if(last<tr[rt].las)
last=tr[rt].las;
x-=tr[rt].val;
tr[rt].same=1;
tr[rt].s=1;
tr[rt].val=0;
tr[rt].fir=0;
tr[rt].las=0;
return ;
}
}
if(tr[rt].l==tr[rt].r)
return ;
Pushdown(rt);
int L=rt<<1,R=rt<<1|1;
if(l<=tr[L].r)
{
if(r<=tr[L].r)
Update1(L,l,r);
else
Update1(L,l,tr[L].r);
}
if(r>=tr[R].l)
{
if(l>=tr[R].l)
Update1(R,l,r);
else
Update1(R,tr[R].l,r);
}
Pushup(rt);
}
void Update2(int rt,int l,int r)
{
if(tr[rt].l==l&&tr[rt].r==r)
{
num+=r-l+1-tr[rt].val;
tr[rt].val=r-l+1;
tr[rt].s=0;
tr[rt].same=1;
tr[rt].fir=l;
tr[rt].las=r;
return;
}
if(tr[rt].l==tr[rt].r)
return ;
Pushdown(rt);
int L=rt<<1,R=rt<<1|1;
if(l<=tr[L].r)
{
if(r<=tr[L].r)
Update2(L,l,r);
else
Update2(L,l,tr[L].r);
}
if(r>=tr[R].l)
{
if(l>=tr[R].l)
Update2(R,l,r);
else
Update2(R,tr[R].l,r);
}
Pushup(rt);
}
int sum(int rt,int l,int r)
{
if(tr[rt].l==l&&tr[rt].r==r)
{
return tr[rt].val;
}
int ans=0;
Pushdown(rt);//因为只是查询,所以区间整体并没有变,就没有必要pushup了;
int L=rt<<1,R=rt<<1|1;
if(l<=tr[L].r)
{
if(r<=tr[L].r)
ans+= sum(L,l,r);
else
ans+= sum(L,l,tr[L].r);
}
if(r>=tr[R].l)
{
if(l>=tr[R].l)
ans+= sum(R,l,r);
else
ans+= sum(R,tr[R].l,r);
}
return ans;
}
int bisearch(int a,int f)
{
if(sum(1,a,n)==0)
return -1;
if(sum(1,a,n)<f)//此处的等于号的问题;
return n;
int l=a,r=n;
int ans=a;
while(l<=r)
{
int mid=(l+r)/2;
if(sum(1,a,mid)>=f)//以及此处的等于号;
{
ans=mid;//这里ans的取值;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i=0;i<m;i++)
{
int ty,z,y;
scanf("%d%d%d",&ty,&z,&y);
if(ty==1)
{
int t=bisearch(z+1,y);
if(t!=-1)
{
x=y;
first=0;
last=0;
Update1(1,z+1,t);
printf("%d %d\n",first-1,last-1);
}
else
printf("Can not put any one.\n");
}
else
{
num=0;
Update2(1,z+1,y+1);
printf("%d\n",num);
}
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: