hdu 4614
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4614
题目大意:n个花瓶,m个操作,k=1 时是从 a 开始插花,如果已经有花,那么跳过,能插多少插多少。k=2,把区间[ a , b ] 内的有的花都清理掉。
思路:裸线段树。就是找区间的时候比较麻烦,其实写两个二分先判断出左右边界就好了。。 时间是 2s ,再乘个 logn 应该也没问题的。。比赛的时候一直卡题,导致后面看到这道裸线段树都懒得去想,懒得去敲了。。 囧
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4614
题目大意:n个花瓶,m个操作,k=1 时是从 a 开始插花,如果已经有花,那么跳过,能插多少插多少。k=2,把区间[ a , b ] 内的有的花都清理掉。
思路:裸线段树。就是找区间的时候比较麻烦,其实写两个二分先判断出左右边界就好了。。 时间是 2s ,再乘个 logn 应该也没问题的。。比赛的时候一直卡题,导致后面看到这道裸线段树都懒得去想,懒得去敲了。。 囧
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 55555 ;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int num[MAXN<<2],dly[MAXN<<2];
void push_up(int rt)
{
num[rt] = num[rt<<1]+num[rt<<1|1];
}
void push_down(int rt,int l,int r,int m)
{
num[rt<<1] = dly[rt]*(m-l+1);
num[rt<<1|1] = dly[rt]*(r-m);
dly[rt<<1] = dly[rt<<1|1] =dly[rt];
dly[rt] = -1;
}
void build(int l,int r,int rt)
{
dly[rt] = -1;
if(l==r)
{
num[rt] = 1 ;
return ;
}
int m = l+r>>1;
build(lson);
build(rson);
push_up(rt);
}
int query(int l,int r,int rt,int a,int b)
{
if(a<=l&&b>=r)
{
return num[rt];
}
int m = l+r>>1;
if(dly[rt]!=-1) push_down(rt,l,r,m);
int cnt1 = 0,cnt2 = 0;
if(a<=m)
cnt1 = query(lson,a,b);
if(b>m) cnt2 = query(rson,a,b);
return cnt1+cnt2;
}
void update(int l,int r,int rt,int a,int b,int c)
{
if(a<=l&&b>=r)
{
dly[rt] = c;
num[rt] = c*(r-l+1);
//printf("l = %d,r = %d,rt = %d,a = %d,b = %d,c = %d,num = %d\n",l,r,rt,a,b,c,num[rt]);
return ;
}
int m = l+r>>1;
if(dly[rt]!=-1)
{
push_down(rt,l,r,m);
}
if(a<=m)
update(lson,a,b,c);
if(b>m) update(rson,a,b,c);
push_up(rt);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
build(0,n-1,1);
int flag,a,b;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&flag,&a,&b);
if(flag==1)
{
int s = query(0,n-1,1,a,n-1);
if(s==0) puts("Can not put any one.");
else
{
int ll,rr;
if(s<=b)
{
b=s;
}
int l = a,r = n-1;
while(l<r)
{
int m = l+r>>1;
int tmp = query(0,n-1,1,a,m);
//printf("l = %d,r = %d,m = %d,tmp = %d\n",l,r,m,tmp);
if(tmp==b)
r = m;
else if(tmp>b)
r = m-1;
else l = m+1;
}
rr = l;
l = a,r = rr;
while(l<r)
{
int m = (l+r+1)>>1;
int tmp = query(0,n-1,1,m,rr);
//printf("l = %d,r = %d,m = %d,tmp = %d\n",l,r,m,tmp);
if(tmp==b)
l = m;
else if(tmp>b)
l = m+1;
else r = m-1;
}
ll = l;
printf("%d %d\n",ll,rr);
update(0,n-1,1,ll,rr,0);
}
}
else
{
printf("%d\n",b-a+1-query(0,n-1,1,a,b));
update(0,n-1,1,a,b,1);
}
}
puts("");
}
return 0;
}
上面那个是用二分的,复杂度上多了个 logn,后来问了下其他人,这道题也可以不用二分,直接用纯线段树的方法做,本来以为找位子会很麻烦,可是经过他们点拨之后,其实也感觉挺简单的,只能说自己的线段树功力还不够吧。就是先把0到一开始尝试放的位子之前有几个空花瓶算出来,记为s,然后找和为s+1的区间,这就是l,然后再找和为s+min(tot,c)(tot为一开始尝试放的位子到n-1的总共空花瓶数,c为放花数),这就是r,然后再更新就好了。个人感觉,把开始放花的边界拓展为0是关键。
具体过程看代码吧,代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int MAXN = 50001 ;
int cnt[MAXN<<2],dly[MAXN<<2];
void push_up(int rt)
{
cnt[rt] = cnt[rt<<1]+cnt[rt<<1|1];
}
void build(int l,int r,int rt)
{
dly[rt] = -1;
if(l==r)
{
cnt[rt] = 1;
return ;
}
int m = l+r>>1;
build(lson);
build(rson);
push_up(rt);
}
void push_down(int rt,int l,int r,int m)
{
cnt[rt<<1] = dly[rt]*(m-l+1);
cnt[rt<<1|1] = dly[rt]*(r-m);
dly[rt<<1] = dly[rt<<1|1] =dly[rt];
dly[rt] = -1;
}
void update(int l,int r,int rt,int a,int b,int c)
{
if(a<=l&&b>=r)
{
dly[rt] = c;
cnt[rt] = c*(r-l+1);
return ;
}
int m = l+r>>1;
if(dly[rt]!=-1) push_down(rt,l,r,m);
if(a<=m) update(lson,a,b,c);
if(b>m) update(rson,a,b,c);
push_up(rt);
}
int query1(int l,int r,int rt,int a,int b)
{
if(a<=l&&b>=r)
{
return cnt[rt];
}
int m = l+r>>1;
if(dly[rt]!=-1) push_down(rt,l,r,m);
int cnt1 = 0,cnt2 = 0;
if(a<=m)
cnt1 = query1(lson,a,b);
if(b>m)
cnt2 = query1(rson,a,b);
return cnt1+cnt2;
}
int query2(int l,int r,int rt,int c)
{
if(l==r)
return l;
int m = l+r>>1;
if(dly[rt]!=-1) push_down(rt,l,r,m);
if(cnt[rt<<1]<c)
{
return query2(rson,c-cnt[rt<<1]);
}
else return query2(lson,c);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
build(0,n-1,1);
int a,b,c;
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
if(a==1)
{
int tot = query1(0,n-1,1,b,n-1);
if(tot==0)
{
puts("Can not put any one.");
continue;
}
c = min(c,tot);
int s;
if(b==0)
s=0;
else s = query1(0,n-1,1,0,b-1);
int l = query2(0,n-1,1,s+1);
int r = query2(0,n-1,1,s+c);
printf("%d %d\n",l,r);
update(0,n-1,1,l,r,0);
}
else
{
printf("%d\n",c-b+1-query1(0,n-1,1,b,c));
update(0,n-1,1,b,c,1);
}
}
puts("");
}
return 0;
}