• BZOJ 3173[Tjoi2013]最长上升子序列(树状数组)


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3173

    题解:话说这道题好像是用splay还是treap来模拟啊,可是我完全不会这两种算法啊。。。无奈,只能去学习了另一种 巧妙的办法。。。。

    1.首先我们先得到最终队列的样子,第i个位置的数字为*i;

    2.按照队列的顺序,i递增,我们用f[*i]来表示当插入*i这个数后,以*i为结尾的最长上升子序列的长度,用k[*i]来储存当前这个数未更新前f[1~*i]中的最大值,我们都知道,平常更新答案是f[i]=max(f[j]+1)即当j<i且*j<*i;那么因为这道题符合一个性质,就是我们是按数字的最终位置一个个插入的,所以我们保证只要f[j]不为0(j<i),那么j这个数字一定在i之前就已经做过了(if (f[j]>0) *j<*i);所以f[*i]一定等于k[*i]+1;

    3.*i这个数字最后的答案为max(f[1~*i]);(因为题目是按数字的大小一个个插入的,所以最优解的结尾数字一定小于等于*i,毕竟其他数字都还没插入。。)

    为了降低时间复杂度,我们用树状数组来维护k数组,复杂度为O(nlogn);

    然后为了方便得出最终的队列的顺序,我学习了如何使用vector,当然,这个时间就变得慢多了。。。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<vector>
    using namespace std;
    int k[2000000],n,p[2000000],f[2000000];
    int lowbit(int x)
    {
      return (x&-x);
    }
    int query(int x)
    {
      int tot=0;
      while (x>0)
      {
          tot=max(tot,k[x]);
          x-=lowbit(x);
      }
      return tot;
    }
    void update(int x,int v)
    {
        while (x<n)
        {
          k[x]=max(k[x],v);
          x+=lowbit(x);
        }
    }
    int main()
    {
      scanf("%d",&n);
      int w;
      vector<int>a;
      for (int i=1;i<=n;i++)
      {
          scanf("%d",&w); 
          a.insert(a.begin()+w,i);//往vector里面插入
      }
      for (vector<int>::iterator i=a.begin();i!=a.end();i++)
       {
    //*i表示在a的里面的第i个元素的值
    //查询max(f[1~*i]);
            f[*i]=query(*i)+1;
    //用树状数组来维护k数组
            update(*i,f[*i]);
       }
      for (int i=1;i<=n;i++) 
      {
       f[i]=max(f[i-1],f[i]);
    //得出最后的答案
       printf("%d
    ",f[i]);
      }
      return 0;
    }
  • 相关阅读:
    查找->静态查找表->顺序查找(顺序表)
    查找(总结篇)
    树和二叉树->其他(待完善)
    树和二叉树->最优二叉树
    树和二叉树->线索二叉树
    树和二叉树->遍历
    树和二叉树->相互转化
    树和二叉树->存储结构
    树和二叉树->基础知识
    P2921-[USACO08DEC]在农场万圣节Trick or Treat on the Farm
  • 原文地址:https://www.cnblogs.com/2014nhc/p/6509596.html
Copyright © 2020-2023  润新知