zoukankan      html  css  js  c++  java
  • 讲课专用——线段树——最长上升子序列

    题目链接:https://www.luogu.org/problemnew/show/P4198

    题解:

    能用线段树解的关键:从第一个位置开始的LIS

    所以说左子区间一定有效,只考虑如何将右子区间与左子区间衔接

    线段树维护从节点区间左端点开始的LIS

    3种情况:

    1、右子区间全都能衔接——右子区间的LIS最小值(第一个位置)> 左子区间LIS最大值

    2、右子区间全都不能衔接——右子区间LIS最大值 <= 左子区间LIS最大值

    3、右子区间后半部分可以衔接——右子区间某一后半部分LIS最小值 > 左子区间LIS最大值

    所以线段树里还要我维护对应的LIS最小值和最大值

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 100000
     
    int len[N<<2|1];
    double mx[N<<2|1],mi[N<<2|1]; 
    
    int n,m;
    int ans;
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } 
    }
    
    void query(int k,int l,int r,double lim)
    {
        if(mi[k]>lim) 
        {
            ans+=len[k];
            return;
        }
        int mid=l+r>>1;
        if(mx[k<<1]>lim) 
        {
            query(k<<1,l,mid,lim);
            query(k<<1|1,mid+1,r,mx[k<<1]);
        }
        else if(mx[k<<1|1]>lim) query(k<<1|1,mid+1,r,lim);
    }
    
    void up(int k)
    {
        int L=k<<1,R=k<<1|1;
        if(mi[R]>mx[L]) 
        {
            len[k]=len[L]+len[R];
            mx[k]=mx[R];
            if(mi[L]) mi[k]=mi[L];
            else mi[k]=mi[R];
        }
        else if(mx[R]<=mx[L]) 
        {
            len[k]=len[L];
            mx[k]=mx[L];
            mi[k]=mi[L];
        }
        else
        {
            ans=len[L];
            query(R,1,n,mx[L]); 
            len[k]=ans;
            mi[k]=mi[L];
            mx[k]=mx[R];
        }
    }
    
    void change(int k,int l,int r,int x,int y)
    {
        if(l==r)
        {
            len[k]=1;
            mx[k]=mi[k]=y*1.0/x;
            return;
        }
        int mid=l+r>>1;
        if(x<=mid) change(k<<1,l,mid,x,y);
        else change(k<<1|1,mid+1,r,x,y);
        up(k);
    }
    
    void init()
    {
        read(n); read(m);
        int x,y; 
        while(m--)
        {
            read(x); read(y);
            change(1,1,n,x,y);
            printf("%d
    ",len[1]);
        }
    }
    
    int main()
    {
        init();
        return 0;
    } 
  • 相关阅读:
    NPM
    Angular2.0快速开始
    AngularJS常用插件与指令收集
    Linq 操作基础
    SQL Server2008 with(lock)用法
    SQL Server2008 MERGE指令用法
    SQL Server2008 表旋转(pivot)技术
    ef to sqlite 实际开发问题终极解决方法
    windows控件常用缩写
    SQL 查询总结
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/11142050.html
Copyright © 2011-2022 走看看