您的位置:首页 > 移动开发

hdu 4266 The Worm in the Apple (线段树)

2015-07-24 20:52 295 查看
/*
题意:给你N个花瓶,编号是0  到 N - 1 ,初始状态花瓶是空的,每个花瓶最多插一朵花。
然后有2个操作。
操作1,a b c ,往在a位置后面(包括a)插b朵花,输出插入的首位置和末位置。
操作2,a b ,输出区间[a , b ]范围内的花的数量,然后全部清空。

很显然这是一道线段树。区间更新,区间求和,这些基本的操作线段树都可以logN的时间范围内完成。
操作2,很显然就是线段树的区间求和,求出[a , b]范围内的花朵的数量,区间更新,将整个区间全部变成0。
操作1,这里我们首先需要找出他的首位置和末位置,所以需要二分他的位置。
首先我们二分他的首位置, l = a , r = n ,在这个区间内二分,找出第一个0的位置,那就是该操作的首位置pos1。
然后再二分他的末位置,l = pos1 , r = n ,找到第b个0,就是该操作的末位置pos2,然后区间更新[pos1 ,pos2]全部置为1。
*/
#include <cstdio>
# include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
///lson和rson分别表示结点的左儿子和右儿子
///rt表示当前子树的根(root),也就是当前所在的结点
const int maxn =60010;
///maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍
int sum[maxn<<2];///求和
int col[maxn<<2];///用来标记每个节点,为0则表示没有标记,否则为标记
int str[maxn];
void PushUP(int rt)///PushUP(int rt)是把当前结点的信息更新到父结点
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void PushDown(int  rt,int  m)///pushDown(int rt)是把当前结点的信息更新给儿子结点,m为分区间的长度
{
if (col[rt])///被标记过,说明区间改变了
{
col[rt<<1] = col[rt<<1|1] = 1;
sum[rt<<1] = (m - (m >> 1)) * col[rt];///更新左儿子的和
sum[rt<<1|1] = (m >> 1) * col[rt];///更新右儿子的和
col[rt] = -1;///将标记向儿子节点移动后,父节点的延迟标记去掉
///传递后,当前节点标记域清空
}
else
{
col[rt<<1] = col[rt<<1|1] = 0;
sum[rt<<1] = sum[rt<<1|1] = 0;
col[rt] = -1;
}
}
void build(int l,int  r,int rt)///建树
{
col[rt] = -1;
if (l == r)
{
sum[rt]=0;
//  scanf("%lld",&sum[rt]);
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUP(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(L <= l && r <= R)
{
col[rt]= c;
sum[rt]= c *(r - l +1);
return;
}
if(col[rt]!=-1)
PushDown(rt , r - l +1);
int m =(l + r)>>1;
if(L <= m) update(L , R , c , lson);
if(R > m) update(L , R , c , rson);
PushUP(rt);
}
int query(int L,int R,int l,int r,int rt)///区间求和
{
if (L <= l && r <= R)
{
return sum[rt];
}
if(col[rt]!=-1)
PushDown(rt , r - l + 1);///要取rt子节点的值时,也要先把rt的延迟标记向下移动
int m = (l + r) >> 1;
int  ret = 0;
if (L <= m) ret += query(L , R , lson);
if (m < R) ret += query(L , R , rson);
return ret;
}
int main()
{
int t,m,n,a,b,c;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
build(1,n,1);
while(m--)
{
scanf("%d",&a);
if(a==1)
{
scanf("%d%d",&b,&c);
b++;
c=min(c,(n-b+1)-query(b,n,1,n,1));
if(c==0)
{
printf("Can not put any one.\n");
continue;
}
int left=b;
int right=n;
while(left<=right)
{
int mid=(left+right)/2;
if(query(b,mid,1,n,1)<mid-b+1)
right=mid-1;
else
left=mid+1;
}
b=left;
right=n;
while(left<=right)
{
int mid=(left+right)/2;
int ans1=query(b,mid,1,n,1);
int ans2=mid-b+1;
int ans=ans2-ans1;
if(ans<c)
left=mid+1;
else
right=mid-1;
}
if(left>n)
left=n;
printf("%d %d\n",b-1,left-1);
update(b,left,1,1,n,1);
}
else
{
scanf("%d%d",&b,&c);
b++;
c++;
if(b>=n)
b=n;
if(c>=n)
c=n;
int ans=query(b,c,1,n,1);
printf("%d\n",ans);
update(b,c,0,1,n,1);
// printf("%d\n",query(b,c,1,n,1));

}
}
printf("\n");
}
return 0;
}
/*
10
10 4
1 2 9
1 0 9
2 0 9
2 0 1
10 5
1 3 5
2 4 5
1 1 8
2 3 6
1 8 8
10 6
1 2 5
2 3 4
1 0 8
2 2 5
1 4 4
1 2 3
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: