BZOJ 2957: 楼房重建

Description

求一个最长上升子序列,支持修改。\(n,m\leqslant 10^5\)

Solution

线段树。

线段树维护区间最大值和区间最长上升子序列长度。

主要的就是一个\(getw(x,v)\),表示\(x\)节点从\(v\)进入后最长上升子序列长度。

两种情况

一种是\(v\geqslant max[lc]\),这时候左子树没贡献,递归右子树。

一种是\(v<max[lc]\),这时候右子树的贡献已经统计过了,就是当前节点最长上升子序列-左节点最长上升子序列,然后递归左子树即可。

复杂度\(O(nlog^2n)\)

Code

/**************************************************************
    Problem: 2957
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:1880 ms
    Memory:5984 kb
****************************************************************/
 
#include <bits/stdc++.h>
using namespace std;
 
const int N = 100050;
 
inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
 
int n,m;
 
struct Seg {
    #define lc (o<<1)
    #define rc (o<<1|1)
    #define mid ((l+r)>>1)
    double mx[N<<2];
    int d[N<<2];
     
    int Getw(int o,int l,int r,double v) {
        if(l==r) return v<mx[o];
        if(mx[lc]<=v) return Getw(rc,mid+1,r,v);
        else return Getw(lc,l,mid,v)+d[o]-d[lc];
    }
    void Update(int o,int l,int r) {
        mx[o]=max(mx[lc],mx[rc]);
        d[o]=d[lc]+Getw(rc,mid+1,r,mx[lc]);
    }
    void Build(int o,int l,int r) {
        if(l==r) { mx[o]=0,d[o]=1;return; }
        Build(lc,l,mid),Build(rc,mid+1,r);
        Update(o,l,r);
    }
    void Modify(int o,int l,int r,int x,double v) {
        if(l==r) { mx[o]=v,d[o]=1;return; }
        if(x<=mid) Modify(lc,l,mid,x,v);
        else Modify(rc,mid+1,r,x,v);
        Update(o,l,r);
    }
}py;
 
int main() {
    n=in(),m=in();
    py.Build(1,1,n);
    for(int x,y;m--;) {
        x=in(),y=in();
        py.Modify(1,1,n,x,(double)y/x);
        printf("%d\n",py.Getw(1,1,n,0));
    }
    return 0;
}

  

posted @ 2017-03-27 08:29  北北北北屿  阅读(84)  评论(0编辑  收藏