zoukankan      html  css  js  c++  java
  • 2019HDU多校 Round6

    Solved:2

    02 Nonsense Time (LIS)

    题意:给定一个全排列 最开始为空的 每秒中一个位置上的数出现 求每秒的LIS

    题解:题解说 考虑时光倒流 倒着消掉 因为数据随机 所以期望的LIS长度为 sqrt(n) 如果每次消失掉的一个数是当前的LIS上的

       就暴力重新求LIS 期望消掉 sqrt(n)个数才会修改LIS 总复杂度 nsqrt(n)logn

    #include <bits/stdc++.h>
    using namespace std;
    
    int n;
    int a[50005];
    int b[50005];
    int d[50005];
    int dp[50005];
    int ans[50005];
    int vis[50005];
    bool vvis[50005];
    
    int LIS() {
        memset(vvis, 0, sizeof(bool) * (n + 2));
        int len = 0;
        d[0] = 0;
        for(int i = 1; i <= n; i++) {
            if(vis[i]) continue;
            if(a[i] > d[len]) d[++len] = a[i], dp[i] = len;
            else {
                int t = lower_bound(d + 1, d + 1 + len, a[i]) - d;
                d[t] = a[i];
                dp[i] = t;
            }
        }
        int tmp = len;
        int now = n + 1;
        for(int i = n; i >= 1; i--) {
            if(vis[i]) continue;
            if(dp[i] == tmp && now > a[i]) {
                vvis[i] = 1;
                tmp--;
                now = a[i];
            }
        }
        return len;
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        while(T--) {
            scanf("%d", &n);
            memset(vis, 0, sizeof(int) * (n + 2));
            for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
            for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
            ans[n] = LIS();
            for(int i = n; i > 1; i--) {
                vis[b[i]] = 1;
                if(vvis[b[i]]) ans[i - 1] = LIS();
                else ans[i - 1] = ans[i];
            }
            for(int i = 1; i <= n; i++) {
                if(i != n) printf("%d ", ans[i]);
                else printf("%d
    ", ans[i]);
            }
        }
        return 0;
    }
    Nonsense Time

    05 Snowy Smile (线段树)

    题意:2000个物品 在坐标上 权值有正有负 求一个矩阵框起来能获得最大价值

    题解:离散化坐标后 按x从小到大排序 这样枚举矩阵的左边界 依次按x往这个矩阵添物品 那么右边界也出来了

       然后在这个左右区间内 用线段树维护纵坐标的最大连续子段和 每次添加完相同横坐标的物品 查询一次

       然后傻傻的我 每次查询按这个左右区间来查询... 查询次数过多 妥妥爆栈了 其实按我的写法 每次更新后.. 不用查询 直接就是根节点的全局答案了

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 2005;
    int n;
    int totx, toty;
    
    struct chest {
        int x, y, w;
        int tx, ty;
    }a[2005];
    
    bool cmp1(chest A, chest B) {
        return A.x < B.x;
    }
    
    bool cmp2(chest A, chest B) {
        return A.y < B.y;
    }
    
    struct node {
        ll sum, ssum, ls, rs;
    }E[MAXN << 2];
    
    void pushup(int rt) {
        int lr = rt << 1;
        int rr = rt << 1 | 1;
        E[rt].ssum = E[lr].ssum + E[rr].ssum;
        E[rt].sum = max(E[lr].sum, E[rr].sum);
        E[rt].sum = max(E[rt].sum, E[lr].rs + E[rr].ls);
        E[rt].ls = max(E[lr].ls, E[lr].ssum + E[rr].ls);
        E[rt].rs = max(E[rr].rs, E[rr].ssum + E[lr].rs);
    }
    
    void build(int l, int r, int rt) {
        if(l == r) {
            E[rt].sum = E[rt].ssum = E[rt].ls = E[rt].rs = 0;
            return;
        }
    
        int mid = l + r >> 1;
        build(l, mid, rt << 1);
        build(mid + 1, r, rt << 1 | 1);
        pushup(rt);
    }
    
    void update(int k, ll v, int l, int r, int rt) {
        if(l == r) {
            E[rt].ssum += v;
            E[rt].sum += v;
            E[rt].ls += v;
            E[rt].rs += v;
            return;
        }
    
        int mid = l + r >> 1;
        if(k <= mid) update(k, v, l, mid, rt << 1);
        else update(k, v, mid + 1, r, rt << 1 | 1);
        pushup(rt);
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        while(T--) {
            totx = toty = 0;
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].w);
            sort(a + 1, a + 1 + n, cmp2);
            for(int i = 1; i <= n; i++) {
                if(a[i].y != a[i - 1].y) a[i].ty = ++toty;
                else a[i].ty = toty;
            }
            sort(a + 1, a + 1 + n, cmp1);
            for(int i = 1; i <= n; i++) {
                if(a[i].x != a[i - 1].x) a[i].tx = ++totx;
                else a[i].tx = totx;
            }
    
            ll ans = 0;
            int las = -1;
            for(int i = 1; i <= n; i++) {
                if(a[i].tx == las) continue;
                build(1, toty, 1);
                int k;
                for(int j = i; j <= n; j = k) {
                    for(k = j; k <= n && a[k].tx == a[j].tx; k++) update(a[k].ty, a[k].w, 1, toty, 1);
                    ans = max(ans, E[1].sum);
                }
                las = a[i].tx;
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    Snowy Smile

       

  • 相关阅读:
    Android标题栏最右边添加按钮
    Activity标题栏添加返回按钮
    【Android】解决Android横竖屏切换数据丢失问题的方法
    Android热更新,到底是更新啥?
    vm ware 虚拟WIN10 时,chrome ,cent browser 显示异常,花屏
    动态生成的 select option 无法选中,设置值
    安装sql 2012 时遇到“需要更新的以前的 Visual Studio 2010 实例。”规则失败。
    C#.NET 简单使用log4net
    10位,13位时间戳转为C#格式时间
    C# .NET Unix 时间戳
  • 原文地址:https://www.cnblogs.com/lwqq3/p/11324054.html
Copyright © 2011-2022 走看看