HDU 4614 Vases and Flowers

HDU 4614 Vases and Flowers

线段树

题意

两个数n,m, n表示花瓶数量0~n-1,开始全为空。接下来有m组,每组有数k,a,b;当k=1时, 从a位置开始插花,b为花数量,当花瓶有花时,跳过当前,直到找到空花瓶再插入,输出插入第一支花的位置和最后一支花的位置,花可以没插完,当一支都没有插入则输出Can not put any one.;当k=2时,清空【a,b】的花瓶,并输出在被清空的花的数量。

思路

线段树用1表示空位,0表示有花。
清空实质就是统计a,b之间有多少花,并把区间a,b强制置1。
插花要有点技巧,设置两个查询函数:查询l,r之间空位的数量,查询从第开头数p个空位到哪。
这样从a开始插b朵花:先查询a到末尾与多少空位x,若x==0输出没法插花;x小于b就把b换成x,实际插x朵;否则插b朵。然后查询开头到a有多少空位k,从开头数k+1个空位到哪,数k+b个空位到哪。这两个数就是实际插花的左右端点。在将这个区间全置0即可。

应该有线段树上二分的写法,可以直接查询从a往右数b个空瓶到哪,可是我不会写。

代码

注意题目从0开始编号,注意转换与边界处理。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=50005;
const int oo=0x3f3f3f3f;
typedef long long LL;
struct Stree
{
    int sum, lpos, rpos;
    int set;
    Stree() { sum=lpos=rpos=0;set=-1; }
    Stree(int _a, int _b, int _c) { sum=_a, lpos=_b, rpos=_c; }
}stree[MAXN<<2];
void pushup(int rt)
{
    stree[rt].sum=stree[rt<<1].sum+stree[rt<<1|1].sum;
    stree[rt].lpos=(stree[rt<<1].lpos==-1 ? stree[rt<<1|1].lpos : stree[rt<<1].lpos);
    stree[rt].rpos=(stree[rt<<1|1].rpos==-1 ? stree[rt<<1].rpos : stree[rt<<1|1].rpos);
}
void build(int l, int r, int rt)
{
    stree[rt].lpos=stree[rt].rpos=stree[rt].set=-1;
    stree[rt].sum=0;
    if(l==r)
    {
        stree[rt].lpos=stree[rt].rpos=l;
        stree[rt].sum=1;
        return;
    }
    int mid=(l+r)>>1;
    build(lson), build(rson);
    pushup(rt);
}
void pushdown(int l, int r, int rt)
{
    if(stree[rt].set!=-1)
    {
        int c=stree[rt].set;
        stree[rt<<1].set=stree[rt<<1|1].set=c;stree[rt].set=-1;
        int mid=(l+r)>>1;
        if(c==0)
        {
            stree[rt<<1].lpos=stree[rt<<1].rpos=stree[rt<<1|1].lpos=stree[rt<<1|1].rpos=-1;
            stree[rt<<1].sum=stree[rt<<1|1].sum=0;
        }
        else
        {
            stree[rt<<1].lpos=l;
            stree[rt<<1].rpos=mid;
            stree[rt<<1|1].lpos=mid+1;
            stree[rt<<1|1].rpos=r;
            stree[rt<<1].sum=mid-l+1;
            stree[rt<<1|1].sum=r-mid;
        }
    }
}
int update(int L, int R, int col, int l, int r, int rt)
{
    if(L<=l&&r<=R)
    {
        if(col==1)
        {
            int c=stree[rt].sum;
            c=r-l+1-c;
            stree[rt].sum=r-l+1;
            stree[rt].set=1;
            stree[rt].lpos=l, stree[rt].rpos=r;
            return c;
        }
        else
        {
            int c=stree[rt].sum;
            stree[rt].sum=0;
            stree[rt].set=0;
            stree[rt].lpos=-1, stree[rt].rpos=-1;
            return c;
        }
    }
    int mid=(l+r)>>1;
    pushdown(l, r, rt);
    int res=0;
    if(midelse if(R<=mid) res=update(L, R, col, lson);
    else res=update(L, R, col, lson)+update(L, R, col, rson);
    pushup(rt);
    return res;
}
int query(int L, int R, int l, int r, int rt)
{
    if(L<=l&&r<=R) return stree[rt].sum;
    pushdown(l, r, rt);
    int mid=(l+r)>>1;
    if(R<=mid) return query(L, R, lson);
    else if(midreturn query(L, R, rson);
    else return query(L, R, lson)+query(L, R, rson);
}
int query_pos(int p, int l, int r, int rt)
{
    if(l==r) return l;
    else if(stree[rt].sum==p) return stree[rt].rpos;
    int mid=(l+r)>>1;
    pushdown(l, r, rt);
    if(stree[rt<<1].sum>=p)
        return query_pos(p, lson);
    else 
        return query_pos(p-stree[rt<<1].sum, rson);
}

int main()
{
    int T;scanf("%d", &T);
    while(T--)
    {
        int n, m;scanf("%d%d", &n, &m);
        build(1, n, 1);
        while(m--)
        {
            int a, b, c;scanf("%d%d%d", &a, &b, &c);
            if(a==1)
            {
                b++;
                int sum=query(b, n, 1, n, 1);
                if(sum==0) puts("Can not put any one.");
                else
                {
                    int pre=(b==1?0:query(1, b-1, 1, n, 1));
                    c=min(c, sum);
                    int l=query_pos(pre+1, 1, n, 1);
                    int r=query_pos(pre+c, 1, n, 1);
                    update(l, r, 0, 1, n, 1);
                    printf("%d %d\n", l-1, r-1);
                }
            }
            else
            {
                printf("%d\n", update(b+1, c+1, 1, 1, n, 1));
            }
        }
        printf("\n");
    }
    //system("pause");
    return 0;
}

你可能感兴趣的:(线段树二分,线段树,2017暑假)