线段树 bzoj2957 楼房重建

大概意思就是求序列从一位置开始的动态上升序列。
分块可过,但这一类题目其实可用线段树。
也就是维护每个区间的上升序列长度。

下面这种求法只是用于当前节点所覆盖的区间完全被查询区间覆盖。
具体而言,查询时如果左儿子的max值< K,只去右儿子找。如果max_lc>=K,那么右儿子的长度全部符合,只要再递归着找左儿子即可。
因为这道题要求的区间是1~n,所以是很裸的题。。。
主体函数


int q(double k,int x)
{
    if(t[x].l==t[x].r)return k<t[x].h;
    if(t[x*2].h<k)return q(k,x*2+1);
    else return q(k,x*2)+t[x].sz-t[x*2].sz;
}
void up(int x)
{
    t[x].h=max(t[x*2].h,t[x*2+1].h);
    t[x].sz=t[x*2].sz+q(t[x*2].h,x*2+1);
}
void C(int l,double k,int x)
{
    if(t[x].l==t[x].r){t[x].sz=1;t[x].h=k;return;}
    int mid=t[x].l+t[x].r>>1;
    if(l<=mid)C(l,k,x*2);
    else C(l,k,x*2+1);
    up(x);
}

那么,对于求给定区间的呢
其实就加了一个地方,只要递归到某个节点被询问区间完全覆盖即可,但要按照顺序枚举,并不断更新当前的最大高度,并累加答案。
多的地方


    int q(int k,int x)
    {
        if(t[x].l==t[x].r){return k<t[x].h;}
        int mid=t[x].l+t[x].r>>1;
        if(t[x*2].h<k)return q(k,x*2+1);
        else return q(k,x*2)+t[x].szr-t[x*2].szr;
    }
    inline void Q_(int l,int r,int x)
    {
        if(t[x].l>=l&&t[x].r<=r)
            {h+=q(mh,x);mh=max(mh,t[x].h);return;}
        int mid=t[x].l+t[x].r>>1;
        if(l<=mid)Q_(l,r,x*2);
        if(r>mid)Q_(l,r,x*2+1);
    } 
    inline int Q(int l,int k)
    {
        h=1;mh=k;Q_(1,l,1);
        return h;
    }

这道题的完整代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define N 100005
using namespace std;
struct tree
{
    int l,r,sz;double h;
}t[N*4];
int n,m;
void build(int l,int r,int x)
{
    t[x].l=l;t[x].r=r;
    if(l==r){t[x].sz=0;t[x].h=0.0;return;}
    int mid=l+r>>1;
    build(l,mid,x*2);
    build(mid+1,r,x*2+1);
}

int q(double k,int x)
{
    if(t[x].l==t[x].r)return k<t[x].h;
    if(t[x*2].h<k)return q(k,x*2+1);
    else return q(k,x*2)+t[x].sz-t[x*2].sz;
}
void up(int x)
{
    t[x].h=max(t[x*2].h,t[x*2+1].h);
    t[x].sz=t[x*2].sz+q(t[x*2].h,x*2+1);
}
void C(int l,double k,int x)
{
    if(t[x].l==t[x].r){t[x].sz=1;t[x].h=k;return;}
    int mid=t[x].l+t[x].r>>1;
    if(l<=mid)C(l,k,x*2);
    else C(l,k,x*2+1);
    up(x);
}
int main()
{
    scanf("%d%d",&n,&m);
    build(1,n,1);int x,y;
    while(m--)
    {
        scanf("%d%d",&x,&y);
        C(x,(double)y/x,1);
        printf("%d\n",q(0,1));
    }
}
posted @ 2017-10-07 13:59  Hzoi_QTY  阅读(132)  评论(0编辑  收藏  举报