• 省队集训 Day3 杨北大


    【题目大意】

    给出平面上$n$个点$(x_i, y_i)$,请选择一个不在这$n$个点之内的点$(X, Y)$,定义$(X, Y)$的价值为往上下左右四个方向射出去直线,经过$n$个点中的数量的最小值。

    Task 1: 求价值最大的点

    Task 2: 求价值最大的点的个数

    保证Task 1和Task 2各占50pts。

    对于30%的数据,$n leq 200$;

    对于60%的数据,$n leq 5000$;

    对于100%的数据,$n leq 300000$。

    每档数据中,50%保证$1 leq x_i, y_i leq n$;50%保证$1 leq x_i, y_i leq 10^9$。

    【题解】

    考场写了60分暴力。。签到题不会打系列。

    回家路上认真想了想,离散后把每个位置用vector存起来。

    二分答案$x$,那么得到的就是若干合法区间(有横的也有竖的),那么一个点只要被一横一竖两个区间同时经过,就有1的贡献,先不考虑$(X, Y)$在$n$个点中的情况,那么这样就能用扫描线+BIT解决了。

    预处理出来对于关键点的贡献,统计的时候减去即可。

    复杂度$O(nlog^2n)$。

    Orz YangPKU

    # include <vector>
    # include <stdio.h>
    # include <assert.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 3e5 + 10;
    const int mod = 1e9+7;
    
    inline int getint() {
        int x = 0; char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x<<3) + (x<<1) + ch - '0', ch = getchar();
        return x;
    }
    
    int n, x[M], y[M], X, Y, ori[M];
    vector<int> psa, psb;
    vector<int> vx[M], vy[M]; int xlen[M], ylen[M];
    
    struct option {
        int op, x, yl, yr, del;
        option() {}
        option(int op, int x, int yl, int yr, int del = 0) : op(op), x(x), yl(yl), yr(yr), del(del) {}
        friend bool operator < (option a, option b) {
            return a.x < b.x || (a.x == b.x && a.op < b.op);
        }
    }o[M * 3]; int on;
    
    struct BIT {
        # define lb(x) (x&(-x))
        ll c[M]; int n;
        inline void set(int _n) {
            n = _n; memset(c, 0, sizeof c);    
        }
        inline void edt(int x, int d) {
            for (; x<=n; x+=lb(x)) c[x] += d;
        }
        inline ll sum(int x) {
            ll ret = 0;
            for (; x; x-=lb(x)) ret += c[x];
            return ret;
        }
        inline ll sum(int x, int y) {
            if(x > y) return 0;
            return sum(y) - sum(x-1);
        }
        # undef lb
    }T;
    
    inline ll chk(int x) {
        ll ans = 0;
        on = 0;
        for (int i=1, l, r; i<=X; ++i) {
            if(xlen[i] >= x + x) {
                l = vx[i][x-1] + 1, r = vx[i][xlen[i]-x] - 1;  
                o[++on] = option(2, i, l, r);    
            }
        }
        for (int i=1, l, r; i<=Y; ++i) {
            if(ylen[i] >= x + x) {
                l = vy[i][x-1] + 1, r = vy[i][ylen[i]-x] - 1;
                o[++on] = option(1, l, i, i, 1);
                o[++on] = option(1, r+1, i, i, -1);
            }
        }
        sort(o+1, o+on+1);
        for (int i=1; i<=on; ++i) {
            if(o[i].op == 1) T.edt(o[i].yl, o[i].del);
            else ans += T.sum(o[i].yl, o[i].yr);
        }
        for (int i=1; i<=n; ++i) ans -= (ori[i] >= x);
        return ans;
    }
    
    int main() {
        int type;
        n = getint(); type = getint();
        for (int i=1; i<=n; ++i) psa.push_back(x[i] = getint()), psb.push_back(y[i] = getint());
        sort(psa.begin(), psa.end()); psa.erase(unique(psa.begin(), psa.end()), psa.end()); X = psa.size();
        sort(psb.begin(), psb.end()); psb.erase(unique(psb.begin(), psb.end()), psb.end()); Y = psb.size();
        for (int i=1; i<=n; ++i) x[i] = lower_bound(psa.begin(), psa.end(), x[i]) - psa.begin() + 1, y[i] = lower_bound(psb.begin(), psb.end(), y[i]) - psb.begin() + 1;
        for (int i=1; i<=n; ++i) vx[x[i]].push_back(y[i]), vy[y[i]].push_back(x[i]);
        for (int i=1; i<=X; ++i) {
            sort(vx[i].begin(), vx[i].end());
            xlen[i] = vx[i].size();
        }
        for (int i=1; i<=Y; ++i) {
            sort(vy[i].begin(), vy[i].end());
            ylen[i] = vy[i].size();
        }
        for (int i=1, xid, yid; i<=n; ++i) {
            xid = lower_bound(vy[y[i]].begin(), vy[y[i]].end(), x[i]) - vy[y[i]].begin();
            yid = lower_bound(vx[x[i]].begin(), vx[x[i]].end(), y[i]) - vx[x[i]].begin();
            ori[i] = min(min(xid, ylen[y[i]]-xid-1), min(yid, xlen[x[i]]-yid-1));
        }
        int l = 0, r = n/4, mid, ans = -1; T.set(Y); ll t;
        while(1) {
            if(r - l <= 3) {
                for (int i=r; i>=l; --i) {
                    if(t = chk(i)) {
                        ans = i;
                        break;
                    }
                }
                break;
            }
            mid = l+r>>1;
            if(chk(mid)) l = mid;
            else r = mid;
        }
        assert(ans != -1);
        if(type == 1) printf("%d
    ", ans);
        else printf("%lld
    ", t);
        return 0;
    }
    View Code
  • 相关阅读:
    char、varchar、nchar、nvarchar的区别
    linux和windows下分别如何查看电脑是32位的还是64位?
    HP-Unix安装Memcache问题
    安装GCC-4.6.1详细教程
    JSTL 核心标签库 使用
    JSP && EL表达式
    UNIX环境高级编程——标准IO-实现查看所有用户
    UNIX环境高级编程——环境变量表读取/添加/修改/删除
    UNIX网络编程——进程间通信概述
    UNIX网络编程——通过UNIX域套接字传递描述符和 sendmsg/recvmsg 函数
  • 原文地址:https://www.cnblogs.com/galaxies/p/20170709_a.html
Copyright © 2020-2023  润新知