1. 程式人生 > >poj-3667(線段樹區間合併)

poj-3667(線段樹區間合併)

題目連結:傳送門

參考文章:傳送門

思路:線段樹區間合併問題,每次查詢到滿足線段樹的區間最左值,然後更新線段樹。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 50500;
int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2],cover[maxn<<2];
void build(int x,int l,int r)
{
    lsum[x]
=rsum[x]=msum[x]=r-l+1; if(l==r) return ; int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); } int MAX(int x,int y) { return x>y?x:y; } void pushup(int x,int k) { lsum[x]=lsum[x<<1]; rsum[x]=rsum[x<<1|1]; msum[x]=MAX(MAX(msum[x<<1
],msum[x<<1|1]),lsum[x<<1|1]+rsum[x<<1]); if(lsum[x<<1]==(k-(k>>1))) lsum[x]+=lsum[x<<1|1]; if(rsum[x<<1|1]==k>>1) rsum[x]+=rsum[x<<1]; } void pushdown(int x,int k) { if(cover[x]!=-1) { cover[x<<1]=cover[x<<1|1
]=cover[x]; lsum[x<<1]=rsum[x<<1]=msum[x<<1]=cover[x]?0:(k-(k>>1)); lsum[x<<1|1]=rsum[x<<1|1]=msum[x<<1|1]=cover[x]?0:(k>>1); cover[x]=-1; } } void update(int x,int l,int r,int A,int B,int Item) { if(A<=l&&r<=B) { cover[x]=Item; lsum[x]=rsum[x]=msum[x]=Item?0:r-l+1; return ; } pushdown(x,r-l+1); int mid=(l+r)>>1; if(A<=mid) update(x<<1,l,mid,A,B,Item); if(B>mid) update(x<<1|1,mid+1,r,A,B,Item); pushup(x,r-l+1); } int query(int x,int l,int r,int len) { if(l==r) return 1; pushdown(x,r-l+1); int mid=(l+r)>>1; if(msum[x<<1]>=len) return query(x<<1,l,mid,len); else if(rsum[x<<1]+lsum[x<<1|1]>=len) return mid-rsum[x<<1]+1; else return query(x<<1|1,mid+1,r,len); } int main(void) { int n,m,i,x,y,z; while(~scanf("%d%d",&n,&m)) { build(1,1,n); while(m--) { scanf("%d",&x); if(x==1) { scanf("%d",&y); if(msum[1]<y) { printf("0\n"); continue; } z=query(1,1,n,y); printf("%d\n",z); update(1,1,n,z,z+y-1,1); } else { scanf("%d%d",&y,&z); update(1,1,n,y,y+z-1,0); } } } return 0; }
View Code

 

http://poj.org/problem?id=3667