Poj 3667 线段树区间合并 (模板)

本文提供了一道来自POJ平台的3667号题目的解决方案,采用段树(区间更新、区间查询最大值、查询前缀和)实现。通过具体的C++代码展示了如何进行区间更新和查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://poj.org/problem?id=3667

别人的分析:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html

#include <iostream>
#include<algorithm>
#include<cstdio>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;
const int maxn=2e5;
int msum[maxn<<2],lsum[maxn<<2],rsum[maxn<<2];
int cover[maxn<<2];
void Pushup(int rt,int len)
{
    lsum[rt]=lsum[rt<<1];
    rsum[rt]=rsum[rt<<1|1];
    if(lsum[rt]==(len-(len>>1)))lsum[rt]+=lsum[rt<<1|1];
       if(rsum[rt]==(len>>1))rsum[rt]+=rsum[rt<<1];
       msum[rt]=max(msum[rt<<1],max(msum[rt<<1|1],rsum[rt<<1]+lsum[rt<<1|1]));
}
void Pushdown(int rt,int len)
{
    if(cover[rt]!=-1)
    {
        cover[rt<<1]=cover[rt<<1|1]=cover[rt];
       msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=cover[rt]?len-(len>>1):0;
          msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=cover[rt]?(len>>1):0;
          cover[rt]=-1;
    }
}
void build(int l,int r,int rt)
{
   msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
   cover[rt]=-1;
   if(l==r)return;
   int m=(l+r)>>1;
   build(lson);
   build(rson);

}
void updata(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        msum[rt]=lsum[rt]=rsum[rt]=c?r-l+1:0;
        cover[rt]=c;
        return;
    }
    Pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)updata(L,R,c,lson);
    if(R>m)updata(L,R,c,rson);
    Pushup(rt,r-l+1);
}
int query(int w,int l,int r,int rt)
{
    if(l==r)return l;
    Pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(msum[rt<<1]>=w)return query(w,lson);
    if((rsum[rt<<1]+lsum[rt<<1|1])>=w)return m-rsum[rt<<1]+1;
    else return query(w,rson);
}
int main()
{
   int t,k,n,a,b,c,i;
   while(~scanf("%d %d",&n,&k)&&n)
   {
       build(1,n,1);
       while(k--)
       {
           scanf("%d",&a);
           if(a==1)
           {
               scanf("%d",&b);
               if(msum[1]<b)printf("0\n");
               else {
                    int s=query(b,1,n,1);
                printf("%d\n",s);
                updata(s,b+s-1,0,1,n,1);
               }
           }
           else
           {
               scanf("%d %d",&b,&c);
               updata(b,c+b-1,1,1,n,1);
           }
       }
   }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值