zoukankan      html  css  js  c++  java
  • UVALive 6261 Jewel heist

    题意:珠宝大盗Arsen Lupin偷珠宝。在展厅内,每颗珠宝有个一个坐标为(xi,yi)和颜色ci。

    Arsen Lupin发明了一种设备,可以抓取平行x轴的一条线段下的所有珠宝而不触发警报,

    唯一的限制是抓取的珠宝不能不能有所有的m种颜色。询问能抓取的最大珠宝数量。

    分析:要决策的东西有两个,一是这条线段的y坐标,二是线段的x的范围。

    枚举线段的y坐标,线段宽度要保证下方不能有所有的颜色,这需要知道颜色的关于x的坐标信息,

    为了x的坐标信息的重复利用,从小到大枚举y。

    对于一个固定的yi,怎么找到合适的区间呢?一个简单且正确的想法是枚举不要的颜色,

    对于每种不要的颜色,只要选择不包含这种颜色的区间就可以保证符号要求了。

    但是这样做太慢了,枚举颜色是O(n)的。

    幸运的是,这里面有大量的重复计算,在枚举yi-1的时候,有很多的区间是不会变的,已经计算过的了,

    只要枚举发生了改变的区间。

    关于颜色的区间信息可以用set保存,在枚举的区间合法的情况下只是一个区间询问单点更新可用BIT,下标范围需要离散。

    /*********************************************************
    *          ----------------------------                  *
    *   author AbyssalFish                                   *
    **********************************************************/
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 2e5+5;
    
    set<int> S[maxn];
    
    int x[maxn],y[maxn],c[maxn];
    int r[maxn], xs[maxn];
    
    int *cmp_c;
    bool cmp_id(int i,int j){ return cmp_c[i] < cmp_c[j]; }
    
    int C[maxn];
    int ns;
    
    void add(int x)
    {
        while(x <= ns){
            C[x]++; x += x&-x;
        }
    }
    
    int sum(int x)
    {
        int re = 0;
        while(x > 0){
            re += C[x]; x &= x-1;
        }
        return re;
    }
    
    
    void solve()
    {
        int n, m, i, j, k;
        scanf("%d%d",&n,&m);
        for(i = 0; i < n; i++) {
            scanf("%d%d%d",x+i,y+i,c+i);
            r[i] = i;
        }
    
        cmp_c = x;
        sort(r,r+n,cmp_id);
        ns = 1;
        xs[r[0]] = ns;
        for(i = 1; i < n; i++){
            xs[r[i]] = (x[r[i]] == x[r[i-1]]) ? ns:++ns;
        }
    
        for(i = 1; i <= m; i++){
            S[i].clear();
            S[i].insert(0);
            S[i].insert(ns+1);
        }
    
        cmp_c = y;
        for(i = 0; i < n; i++) r[i] = i;
        sort(r,r+n,cmp_id);
    
        memset(C+1,0,sizeof(int)*ns);
    
        int ans = 0, p, q, cur_y;
        for(i = 0; i < n; i = k){
            cur_y = y[r[i]];
            for(j = i; j < n && y[k = r[j]] == cur_y; j++){
                auto it = S[c[k]].lower_bound(xs[k]);
                p = *it-1;
                q = *--it;
                if(p > q)
                    ans = max(ans,sum(p)-sum(q));
            }
            k = j;
            while(--j >= i){
                p = r[j];
                S[c[p]].insert(xs[p]);
                add(xs[p]);
            }
        }
        for(i = 1; i <= m; i++){
            auto it = S[i].begin();
            q = 0;
            for(it++; it != S[i].end(); it++){
                p = *it-1;
                if(p > q) ans = max(ans, sum(p) - sum(q));
                q = *it;
            }
        }
        printf("%d
    ", ans);
    }
    
    //#define LOCAL
    int main()
    {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif
        int T; scanf("%d",&T);
        while(T--) solve();
        return 0;
    }
  • 相关阅读:
    shell脚本编程-结构化命令3-while、until命令
    shell脚本编程-结构化命令2-for命令
    sscanf解析复杂字符串,双引号通配符的使用问题
    shell脚本编程-结构化命令1-分支语句
    shell脚本编程基础
    linux系统管理的基本命令2
    linux系统管理的基本命令
    redis
    Eclipse启动报错
    java斗地主发牌源码
  • 原文地址:https://www.cnblogs.com/jerryRey/p/5043776.html
Copyright © 2011-2022 走看看