zoukankan      html  css  js  c++  java
  • CH暑假欢乐赛 SRM 07 天才麻将少女KPM(DP+treap)

      首先LIS有个$O(n^2)$的DP方法

      $f(i,j)$表示前i个数,最后一个数<=j的LIS

      如果$a_i!=0$则有

      如果$a_i=0$则有

      注意因为$f(i-1,j)leq f(i-1,j-1)+1$,所以上面第二个转移是成立的。

      用treap维护这个有两种写法。

      ①支持区间max=,区间+1。

      ②只要是只要求单点查询或者最后输出答案的区间操作都是可以用差分的。

      这题显然两个条件都满足233

      每次对一个区间+1的时候,实际上就是区间后移一位,直接插入一个点即可,然后l所在位置+1,(r+1)所在位置-1,但是这题我们维护的是前缀max,所以每个点的信息其实是前面任意一个地方的差分值里最大的,所以我们不能-1,而是如果区间右端点右边还有+1的话,就删掉最近的一个。

      $a_i=0$时,区间为$[l,r]$,$a_i!=0$,区间看成是$a_i$这个点。

      好像写丑了跑得很慢

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #define lt tree[x].ls
    #define rt tree[x].rs
    using namespace std;
    const int maxn=500010;
    struct poi{int ls, rs, sum, rnd, size, w;}tree[maxn];
    int n, l, r, tott, root, tmp, mx, now, cnt;
    int a[maxn];
    inline void read(int &k)
    {
        int f=1; k=0; char c=getchar();
        while(c<'0' || c>'9') c=='-' && (f=-1), c=getchar();
        while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
        k*=f;
    }
    inline void build(int &x, int delta)
    {
        tree[x=++tott].w=tree[x].sum=delta;
        tree[x].rnd=rand()<<15|rand();
        tree[x].size=1;
    }
    inline void up(int x)
    {
        tree[x].size=tree[lt].size+tree[rt].size+1;
        tree[x].sum=tree[lt].sum+tree[rt].sum+tree[x].w;
    }
    void split(int x, int &l, int &r, int k)
    {
        if(!k) l=0, r=x;
        else if(tree[x].size==k) l=x, r=0;
        else if(tree[lt].size>=k) r=x, split(lt, l, lt, k), up(x);
        else l=x, split(rt, rt, r, k-tree[lt].size-1), up(x);
    }
    void merge(int &x, int l, int r)
    {
        if(!l || !r) x=l+r;
        else if(tree[l].rnd>tree[r].rnd) x=l, merge(rt, rt, r), up(x);
        else x=r, merge(lt, l, lt), up(x);
    }
    void find(int x)
    {
        if(tree[lt].sum) return find(lt);
        now+=tree[lt].size+1;
        if(tree[x].w) return;
        if(tree[rt].sum) return find(rt);
    }
    void del(int &root, int rk)
    {
        int x, y, z;
        split(root, x, y, rk); split(x, z, x, rk-1);
        merge(root, z, y);
    }
    inline void solve(int l, int r)
    {
        int x, y, z;
        build(tmp, 1); split(root, x, y, l-1);
        merge(x, x, tmp); merge(root, x, y);
        split(root, x, y, r); 
        if(tree[y].sum) {now=0; find(y); del(y, now);}
        merge(root, x, y);
        split(root, x, y, mx); merge(root, x, y);
    }
    int main()
    {
        read(n); read(l); read(r); tree[0].rnd=(1ll<<31)-1; mx=r;
        for(int i=1;i<=n;i++) read(a[i]), mx=max(mx, a[i]);
        for(int i=1;i<=mx;i++) build(tmp, 0), merge(root, root, tmp);
        for(int i=1;i<=n;i++)
        if(a[i]) solve(a[i], a[i]); else solve(l, r);
        int x, y; split(root, x, y, mx);
        printf("%d
    ", tree[x].sum);
    }
    View Code
  • 相关阅读:
    RESTful规范
    浏览器缓存(强缓存和协商缓存)
    react hooks useState更新数据不及时问题及处理
    css提升页面渲染新属性content-visibility
    Mongodb Sort Operations
    mongodb使用小点
    Visual Studio 2017 中的Git源代码控制中使用BeyondCompare 3
    “指纹登录“ -- 项目中用到的两个cordova插件基本使用
    代码段:通过索引获取对应的Excel列名; 索引从0开始,返回形如 A,B,C,...,Z,AA,AB,...,AZ,BA,...,ZZ,AAA,AAB,......
    初学knockoutjs记录9——Bindings 绑定(1 Controling text and appearance 控制文本和外观)
  • 原文地址:https://www.cnblogs.com/Sakits/p/8110744.html
Copyright © 2011-2022 走看看