G - Vases and Flowers(线段树+二分)

http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=216#problem/G


有n个花盆编号0-n-1,初始都没有种花,有两种操作:

1 a b 从a开始种花,但a处不一定能种,要种b朵花,若花盆中已种花就跳过不种,直到n-1,若b朵花种不完就扔掉,输出种b朵花的花盆左右端点。

2 a b要清理[a,b]的花盆,先输出[a,b]的花的数目,然后清空这些花。


第二种操作简单,重点是第一种操作,寻找左右端点都是二分查找,首先应该找出从a起第一个能种花的花盆l,然后根据左端点l二分处右端点r使得[l,r]的能种花的个数是b。


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#define LL long long
#define LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 500010;

struct node
{
    int l,r;
    int sum;
    int col;
} tree[maxn*4];

void build(int v, int l, int r)
{
    tree[v].l = l;
    tree[v].r = r;
    tree[v].sum = 0;
    tree[v].col = 0;
    if(l == r)
        return;
    int mid = (l+r) >> 1;
    build(v*2,l,mid);
    build(v*2+1,mid+1,r);
}

void push_down(int v)
{
    if(tree[v].l == tree[v].r || tree[v].col == -1)
        return;
    tree[v*2].col = tree[v*2+1].col = tree[v].col;
    if(tree[v].col == 1)
    {
        tree[v*2].sum = tree[v*2].r - tree[v*2].l + 1;
        tree[v*2+1].sum = tree[v*2+1].r - tree[v*2+1].l + 1;
    }
    else
        tree[v*2].sum = tree[v*2+1].sum = 0;
    tree[v].col = -1;
}

int query(int v, int l, int r)
{
    if(tree[v].l == l && tree[v].r == r)
        return tree[v].sum;

    push_down(v);
    int mid = (tree[v].l + tree[v].r)>>1;
    if(r <= mid)
        return query(v*2,l,r);
    else if(l > mid)
        return query(v*2+1,l,r);
    else return query(v*2,l,mid) + query(v*2+1,mid+1,r);
}

int Binsearch(int l, int r, int key)
{
    int low = l,high = r,mid;
    int res;
    while(high >= low)
    {
       mid = (low + high) >> 1;
	   res =  query(1,l,mid);
        if(mid-l+1 - res < key)
            low = mid+1;
        else high = mid-1;
    }
    return low;
}

void update(int v, int l, int r, int col)
{
    if(tree[v].l == l && tree[v].r == r)
    {
        tree[v].col = col;
        if(tree[v].col == 1)
            tree[v].sum = tree[v].r - tree[v].l + 1;
        else tree[v].sum = 0;
        return;
    }

	push_down(v);
	int mid = (tree[v].l + tree[v].r) >> 1;
	if(r <= mid)
		update(v*2,l,r,col);
	else if(l > mid)
		update(v*2+1,l,r,col);
	else
	{
		update(v*2,l,mid,col);
		update(v*2+1,mid+1,r,col);
	}
	tree[v].sum = tree[v*2].sum + tree[v*2+1].sum;
}

int main()
{
    int test;
    int n,m,a,b,res,l,r,res1,op;
    scanf("%d",&test);
    while(~scanf("%d %d",&n,&m))
    {
        build(1,0,n-1);
        while(m--)
        {
            scanf("%d %d %d",&op,&a,&b);
            if(op == 1)
            {
                res = query(1,a,n-1);
                if(n-a == res)
                    printf("Can not put any one.\n");
                else
                {
                	if(a == 0)
						res1 = 0; //wa了一次,a=0时a-1越界。
                    else res1 = query(1,0,a-1); //询问[0,a-1]的已种的花
                    l = Binsearch(0,n-1,a-res1+1);//二分查找[0,n-1]中的l使得[0,l]的可以种的花为a-res1+1,这个l就是要找的左端点

                    b = min(n-a-res,b);//b取[a,n-1]可以种的花数与b的较小值
                    r = Binsearch(l,n-1,b);//二分查找r使得[l,r]中可以种的花为b
                    printf("%d %d\n",l,r);
                    update(1,l,r,1);
                }
            }
            else
            {
                res = query(1,a,b);
                printf("%d\n",res);
                update(1,a,b,0);
            }
        }
        printf("\n");
    }
    return 0;
}




你可能感兴趣的:(数据结构-线段树&树状数组)