hdu 4614 线段树 二分

摘要:
如果你能放但不能放所有的花,输出n是很好的。第二种方法是在间隔[A,B]之间清空花瓶中的花。输出这次清除了多少花。思路:第二种方法显然可以用线段树来实现。第一个是如何使用线段树通过二分法和线段树确定右端点的位置。这样,第一个操作是间隔更新,并使用namespacestd#definelllong#definepbpush_back#definempmake_pair#definelsonl,mid,rt˂˂1#definersonmid+1,r,rt˂˂1|1#definefirst#definesecondconstintN=5E4+3;常数M=5e4+3;整数,m;整数和[N˂˂2],fst[N˂˂2],las[N˂˂02],L[N˂[2],R[N˂2];整数[N˂˂2];//第一个开始空las最后一个空和空数量void pushup{sum[rt]=sum[rt˂˂1]+sum[rt˂˂1|1];如果(las[rt˂˂1|1]!

题意:有n个花瓶,每个花瓶中只能放一朵花。

两种操作,一种是从A开始放F朵花,如果有的花瓶中已经有花则跳过这个花瓶,往下一个花瓶放;

输出这次放的花的左右端点。如果能放但是放不完f朵输出n就好了

第二种是将区间[A,B]之间花瓶中的花清空。输出这次总共清理出了多少支花。

思路:第二种很明显可以用线段树实现,问题在第一种如何用线段树实现

用二分 和 线段树 来判断右端点的位置 这样就可以了 第一次操作就成了区间更新

并且查询左右端点

#include<cstdio>#include<cstring>#include<iostream>#include<vector>
using namespacestd;

#define ll long long
#define pb push_back
#define mp make_pair
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define fi first
#define se second
const int N = 5E4+3;
const int M  = 5e4+3;

intn,m;
int sum[N<<2],fst[N<<2],las[N<<2],L[N<<2],R[N<<2];
int col[N<<2];
//fst 开始空的  las最后空的  sum 空的数量
void pushup(intrt){
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
    if(las[rt<<1|1]!=-1)
        las[rt]=las[rt<<1|1];
    else las[rt]=las[rt<<1];
    if(fst[rt<<1]!=-1)
        fst[rt]=fst[rt<<1];
    else fst[rt] = fst[rt<<1|1];
    R[rt] = R[rt<<1|1];
    L[rt] = L[rt<<1];
}

void pushdown(intrt){
    //添加
    if(col[rt]==1){
        col[rt<<1]=col[rt<<1|1] =col[rt];
        sum[rt<<1]  = 0;
        sum[rt<<1|1] = 0;
        las[rt<<1]=las[rt<<1|1] = -1;
        fst[rt<<1]=fst[rt<<1|1] =-1;
        col[rt]=0;
    }
    else if(col[rt]==-1){
        col[rt<<1]=col[rt<<1|1] =col[rt];
        sum[rt<<1] = R[rt<<1]-L[rt<<1]+1;
        sum[rt<<1|1] = R[rt<<1|1]-L[rt<<1|1]+1;
        las[rt<<1] = R[rt<<1];
        fst[rt<<1] = L[rt<<1];
        las[rt<<1|1] = R[rt<<1|1];
        fst[rt<<1|1] = L[rt<<1|1];
        col[rt]=0;
    }
}

void build(int l,int r,intrt){
    col[rt] =0;
    if(l==r){
        L[rt] =r;
        R[rt] =l;
        sum[rt]=1;
        las[rt]=r;
        fst[rt]=l;
        return;
    }
    int mid = (l+r)/2;
    build(lson);build(rson);
    pushup(rt);
}

void update(int l,int r,int rt, int a,int b,intval){

    if(a<=l && b>=r){

        if(val==1){
           if(sum[rt] ==0)return;
            col[rt] =val;
            sum[rt] = 0;
            las[rt]=fst[rt]=-1;
        }
        else if(val==-1){
            if(sum[rt]==R[rt]-L[rt]+1)return;
          //printf("%d %d %d %d %d %d
",l,r,rt,a,b,sum[rt]);
            col[rt]=val;
            sum[rt]= R[rt]-L[rt]+1;
            las[rt]=R[rt];
            fst[rt]=L[rt];
           //printf("gai: %d %d %d %d %d %d
",l,r,rt,a,b,sum[rt]);
}
        return;
    }

    pushdown(rt);

     int mid=(l+r)/2;
     if( a<=mid ) update(lson,a,b,val);
     if( b>mid ) update(rson ,a,b,val);
     pushup( rt );

}

int qfst(int l,int r,int rt,int a,intb){
    if(a<=l && b>=r){
        returnfst[rt];
    }
    pushdown(rt);
    int mid =(l+r)/2;
    if(b<=mid)returnqfst(lson,a,b);
    else if( a>mid )returnqfst(rson,a,b);
    else{
        int ans1=-1;
        if(a<=mid)
            ans1 =qfst(lson,a,b);
        if(ans1!=-1)returnans1;
        if(b>mid)
        returnqfst(rson,a,b);
    }
}

int qlst(int l,int r,int rt,int a,intb){
     if(a<=l && b>=r){
        returnlas[rt];
    }
     pushdown(rt);
    int mid =(l+r)/2;
    if(b<=mid)returnqlst(lson,a,b);
    else if(a>mid)returnqlst(rson,a,b);
    else{
        int ans1=-1;
        if(b>mid)
            ans1=qlst(rson,a,b);
        if(ans1!=-1)returnans1;
        if(a<=mid)returnqlst(lson,a,b);
    }
}

int qnum(int l,int r,int rt,int a,intb){
    if(a<=l && b>=r){
        //printf("get :%d %d %d %d %d %d
",l,r,rt,a,b,sum[rt]);
        int res =sum[rt];
        returnres;
    }
    pushdown(rt);
    int ans = 0;
    int mid =(l+r)/2;
    if(a<=mid)
        ans+=qnum(lson,a,b);
    if(b>mid)
        ans+=qnum(rson,a,b);
    returnans;
}

int b_s(int st,intneed){

    int l=st,r=n;
    int res = qnum(1,n,1,st,n);
    if(res==0)return -1;
    if(res<need)returnn;
    int ans =n;
    while(l<=r){
        int m = (l+r)/2;
        if(qnum(1,n,1,st,m)>=need){
            ans =min(ans,m);
            r=m-1;
        }
        else l= m+1;
    }
    returnans;
}

intmain(){

    intt;
    cin>>t;
    intop;
    while(t--){
        scanf("%d %d",&n,&m);

        build(1,n,1);

        while(m--){
            scanf("%d",&op);
            if(op==1){
                int x,f;scanf("%d %d",&x,&f);
                x++;
                int v =b_s(x,f);
                if(v==-1){
                    printf("Can not put any one.
");
                }
                else{
                    printf("%d %d
",qfst(1,n,1,x,v)-1 ,qlst(1,n,1,x,v)-1);
                    update(1,n,1,x,v,1);
                }
            }
            else if(op==2){
                int a,b;scanf("%d %d",&a,&b);
                a++;b++;
                int res = qnum(1,n,1,a,b);
                printf("%d
",b-a+1-res);
                update(1,n,1,a,b,-1);
              //cout<<sum[24]<<"!!"<<endl;
                res = qnum(1,n,1,a,b);
              //printf("update : %d
",b-a+1-res);
}
        }
        cout<<endl;
    }
    return 0;
}

免责声明:文章转载自《hdu 4614 线段树 二分》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇JQuery 限制文本输入只能输入数字(可自定义正则表达式)实战:一种在http请求中使用protobuffer+nginx+lua收集打点日志的方案下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

[POJ1195] Mobile phones(二维树状数组)

题目链接:http://poj.org/problem?id=1195 题意:四种操作: 0:初始化一个S*S的零矩阵 1:点(x,y)是值+A 2:查询一个子矩阵里所有数的和 3:退出 线段树由于不能在两棵树之间传递标记,所以这种求和的操作非常难处理。 改学了一下而为树状数组,发现可是比二维线段树简单多了。 记得之前曾经看过zkw线段树的ppt讲稿,好像...

[题解] bzoj 3600 没有人的算数 (替罪羊树+线段树)

- 传送门 - http://www.lydsy.com/JudgeOnline/problem.php?id=3600   - 思路 - 区间操作是线段树无疑,难点在于如何考虑这些数对的大小关系. 我们考虑一下平衡树,如果在平衡树中每个节点放一个数对,我们规定中序遍历前面的数对大于后面的,那么对于任意一个新数对(x,y)插入时只需知道x,y与每个节点的数...

CF981E Addition on Segments(线段树分治+bitset)

观察本题,我们发现,如果某些操作每次都更新到了某个位置,那么我们可以通过维护bitset来发现这个对于这个位置来说的可能最大值 而且答案就是所有位置取一下或。因为我们发现对于每个位置,bitset上为1的那些数一定可以取到最大值。 但是这样过于暴力,我们发现这是一个区间操作,而区间操作一般和线段树相结合,因此采用线段树分治,先对这段操作影响到的区间打标记...

[BZOJ 1568][JSOI2008]Blue Mary开公司

[BZOJ 1568][JSOI2008]Blue Mary开公司 题意 (n) 次操作, 维护一个一次函数集合 (S). 有两种操作: 给定 (b) 和 (k), 向 (S) 中插入一个函数 (f(x)=kx+b). 给定一个 (x), 求 (maxlimits_{fin S}{f(x)}). (nle 1 imes 10^5,xle 50000)....

线段树_模版

线段树 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。 区间修改与求和 给出数的个数n以及操作数q:对于q:...

4.18 省选模拟赛 消息传递 树剖 倍增 线段树维护等比数列

把树剖和倍增 线段树的联系诠释的很完美。 题目意思:自行理解。 做法:设两个点x,y x能挡住y 且在k点处 那么至少的得到一个式子 tx+dx-dk<tx+dy-dk 从这个式子中可以发现 按tx+dx这个排序 前面的可以有可能挡住后面的 同时相等时题目中的要求小的编号优先。 我们考虑一个点挡住当前的这个点的去路 设sx表示x这个点当前不能通过的...