zoukankan      html  css  js  c++  java
  • 2020 5 27 树状数组

     这是一个比较显然的dp,最长不下降子序列。
    但是他要求的时间是O(nlogn),而且还要求的是求方案数。
    原本的dp是O(n^2)的,会TLE
    可以发现,其实这个是可以把方案数和dp值放在一起维护的。
    我们就建一个树状数组,其中第x个数放的是当电阻小于x时的方案数和最长长度
    每当读入一个数的时候,就先取出小于这个数的最长不下降子序列的数量
    把取出的方案数++,因为加入了一个数,肯定是能够多至少一种方案的。
    在用这个去尝试更新答案。
    最后把这个数也加入树状数组,把它的全部能提供的方案数和价值也记录一下
    如果在记录的时候,也就是树状数组使用它O(logn)的方法进行更改的时候,发现了长度的变化,那么就直接更新这个点答案就好了
    其实这个进行更改的过程就是原来的dp的过程
    但是因为是树状数组,更改仅仅是使用了O(logn)的时间就更改了全部的答案。
    所以就很快了啦awa
    但是为什么树状数组能维护的怎么好呢?仅仅是用了logn的时间就完成了O(n)的事情
    主要是因为在原本的dp中,每一次的枚举上一个决策点都使用了大量的时间。这是没有必要的。
    我们完全可以维护每一个决策点来使dp快速转移。
    或者说是,其实每一个树状数组的汇合的点,就是储存了最优的决策的点,这个点中的决策时保证在目前情况下最优的。
    那么,如果我更新的是这个点,就说明这个点的答案肯定是不行的了。到最后也是一样的。
    至于方案数和这个是没关系的啦awa
    方案数懒的搞了awa
    各位dalao之间看代码吧awa
    CODE

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int mod=123456789;
    inline ll read()
    {
        char c=getchar();ll a=0,b=1;
        for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
        for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;
        return a*b;
    }
    int n,type,a[1000001];
    struct tree
    {
        int v,s;//长度,方案数
        inline void clear()
        {
            v=0;
            s=1;
            return;
        }
    }t[1000001];
    int lowbit(int x)
    {
        return x&(-x);
    }
    inline int change(int x,tree y)
    {
        while(x<=100000)
        {
            if(t[x].v<y.v)
            {
                t[x]=y;
            }
            else
            {
                if(y.v==t[x].v)
                {
                    t[x].s+=y.s;
                    t[x].s%=mod;
                }
            }
            x+=lowbit(x);
        }
    }
    inline tree ask(int x)
    {
        tree res;
        res.clear();
        while(x>0)
        {
            if(t[x].v>res.v)
            {
                res=t[x];
            }
            else
            if(res.v==t[x].v)
            {
                res.s+=t[x].s;
                res.s%=mod;
            }
            x-=lowbit(x);
        }
        return res;
    }
    inline tree changeans(tree x,tree y)
    {
        if(x.v<y.v)
        {
            return y;
        }
        else
        {
            if(x.v==y.v)
            {
                x.s+=y.s;
                x.s%=mod;
                return x;
            }
        }
        return x;
    }
    int main()
    {
        tree ans;ans.clear();
        n=read();type=read();
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            tree x=ask(a[i]-1);
            x.v++;
            ans=changeans(ans,x);
            change(a[i],x);
        }
        cout<<ans.v%mod<<endl;
        if(type==1)cout<<ans.s%mod<<endl;
        return 0;
    }
  • 相关阅读:
    剑指offer---第一个只出现一次的字符
    剑指offer---两个链表的第一个公共结点
    剑指offer---丑数
    剑指offer---旋转数组的最小数字
    剑指offer---滑动窗口的最大值
    剑指offer---重建二叉树
    剑指offer---数据流中的中位数
    剑指offer---二叉搜索树的第K个节点
    剑指offer--对称二叉树
    剑指offer---把二叉树打印成多行
  • 原文地址:https://www.cnblogs.com/HLZZPawa/p/12973622.html
Copyright © 2011-2022 走看看