• bzoj3173: [Tjoi2013]最长上升子序列(树状数组+二分倒推)


    3173: [Tjoi2013]最长上升子序列

    题目:传送门


    题解:

       好题!

       怎么说吧...是应该扇死自己...看错了两次题:

       每次加一个数的时候,如果当前位置有数了,是要加到那个数的前面,而不是直接替代ORZ

       那么我们可以用二分倒推出最终数列,顺便记录位置

       那么最后问题就变成给你一列数,nlogn求最长上升子序列啦


    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 int n;
     8 int a[110000],s[110000];
     9 int lowbit(int x){return x&-x;}
    10 void change_max(int x,int p){while(x<=n)s[x]=max(s[x],p),x+=lowbit(x);}
    11 void change_sum(int x){while(x<=n)s[x]++,x+=lowbit(x);}
    12 int find_max(int x){int ans=0;while(x)ans=max(ans,s[x]),x-=lowbit(x);return ans;}
    13 int find_sum(int x){int ans=0;while(x)ans+=s[x],x-=lowbit(x);return ans;}
    14 int main()
    15 {
    16     scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]++;//位置++ 
    17     for(int i=n;i>=1;i--)//倒推位置 
    18     {
    19         int l=1,r=n;
    20         while(l<r)
    21         {
    22             int mid=(l+r)/2;//二分位置 
    23             int cnt=mid-find_sum(mid);//看一下当前位置前面已经有多少个数了 
    24             if(cnt<a[i])l=mid+1;//因为如果有重复的话是放在前面,所以是小于号 
    25             else r=mid;
    26         }
    27         a[i]=l;change_sum(a[i]);
    28     }
    29     memset(s,0,sizeof(s));
    30     int ans=0;
    31     for(int i=1;i<=n;i++)
    32     {
    33         int cnt=find_max(a[i])+1;//算上自己就要加 1 
    34         change_max(a[i],cnt);
    35         ans=max(ans,cnt);
    36         printf("%d
    ",ans);
    37     }
    38     return 0;
    39 }
  • 相关阅读:
    雅虎35条优化黄金守则
    安装入门
    NPOI 2.0 Excel读取显示
    STL算法
    MVVM框架avalon在兼容旧式IE
    Asp.Net MVC3.0网站统计登录认证的在线人数
    Windows Server 服务器安全配置
    SignalR的服务器广播
    angularjs + seajs构建Web Form3
    MVC应用程序显示上传的图片
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8540410.html
Copyright © 2020-2023  润新知