省队集训 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\n", ans);
    else printf("%lld\n", t);
    return 0;
}

时间: 2024-11-08 19:07:45

省队集训 Day3 杨北大的相关文章

bzoj4171 or 省队集训day3 chess: Rhl的游戏

[题目描述] RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色.每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子),黑变白,白变黑. RHL希望把所有格子都变成白色的.不幸的是,有一些格子坏掉了,无法被按下.这时,它可以完成游戏吗? [输入格式] 第一行一个整数T,表示T组数据. 每组数据开始于三个整数n,m,k,分别表示格子的高度和宽度.坏掉格子的个数.接下来的n行,每行一个长度m

2015湖南省队集训DAY3——Light

Light [问题描述] "若是万一琪露诺(俗称 rhl)进行攻击,什么都好,冷静地回答她的问题来吸引 对方表现出兴趣的话,那就慢慢地反问.在她考虑答案的时候,趁机逃吧.就算是很简 问题,她一定也答不上来." --<上古之魔书> 天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列 a[i],远 魔书上记载到:2 个位置的 graze 值为两者位置差与数值差的和: graze(x,y)=|x-y|+|a[x]-a[y]|. 要想破解天罚,就必须支持 2种操作(

FJ省队集训DAY3 T1

思路:我们考虑如果取掉一个部分,那么能影响到最优解的只有离它最近的那两个部分. 因此我们考虑堆维护最小的部分,离散化离散掉区间,然后用线段树维护区间有没有雪,最后用平衡树在线段的左右端点上面维护最小的id 我讲的貌似不是很清楚.. 还有,蜜汁80分,打死也改不出来.. 1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<cstring> 5 #include<algo

FJ省队集训DAY3 T2

思路:如果一个DAG要的路径上只要一条边去切掉,那么要怎么求?很容易就想到最小割,但是如果直接做最小割会走出重复的部分,那我们就这样:反向边设为inf,这样最小割的时候就不会割到了,判断无解我们直接用tarjan 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define ll long

省队集训 Day3 陈姚班

[题目大意] 给一张网格图,上往下有流量限制,下往上没有,左往右有流量限制. $n * m \leq 2.5 * 10^6$ [题解] 考场直接上最大流,50分.竟然傻逼没看出狼抓兔子. 平面图转对偶图,其中没有流量限制(inf)不用转,然后直接在DAG上分层dp即可. 复杂度$O(nm)$,但是这样过不去被卡常了. 出题人的做法是先处理出每层初始的那个随机数,然后每层往下直接做,这样因为是一维数组,所以寻址方便,不会被卡常. 我的做法是动态开数组(用new),然后比较两维大小来分配第一维给谁,

省队集训 Day3 吴清华

[题目大意] 给网格图,共有$n * n$个关键节点,横向.纵向距离均为$d$,那么网格总长度和宽度均为$(n+1) * d + 1$,最外围一圈除了四角是终止节点.要求每个关键节点都要通过线连向终止节点,每个点只能连一条线,线不能相交,且只能连在网格的边上. 求最短布线距离.提交答案题. [题解] 前面3个点(60分)可以跑费用流,这是一个经典拆点费用流模型,大概并行跑个15min也就出来了. 后面2个点据说用原始对偶跑会快很多,ditoly后两个点就跑了36分. orz ditoly

省队集训Day3 tree

[题目描述] RHL 有一天看到 lmc 在玩一个游戏. “愚蠢的人类哟,what are you doing”,RHL 说. “我在玩一个游戏.现在这里有一个有 n 个结点的有根树,其中有 m 个叶子结点.这 m个叶子从 1 到 m 分别被给予了一个号码,每个叶子的号码都是独一无二的.一开始根节点有一个棋子,两个玩家每次行动将棋子移动到当前节点的一个儿子节点.当棋子被移动到某个叶节点的时候游戏结束,这个叶节点的号码即为该局游戏的 result.先手的玩家要最大化result,后手的玩家要最小化

省队集训Day3 light

[问题描述] “若是万一琪露诺(俗称 rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她.对方表现出兴趣的话,那就慢慢地反问.在她考虑答案的时候,趁机逃吧.就算是很简单的问题,她一定也答不上来.” ——<上古之魔书> 天空中出现了许多的北极光,这些北极光组成了一个长度为 n 的正整数数列 a[i],远古之魔书上记载到:2 个位置的 graze 值为两者位置差与数值差的和: graze(x,y)=|x-y|+|a[x]-a[y]|. 要想破解天罚,就必须支持 2 种操作(k 都是正整数):

JS省队集训记

不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么心态? T2 唉,感觉好像做过类似的? T3 唉,怎么是提交答案题…… 感觉前两题都会,信心大增,于是决定先码T2 码了一会,过了第二个样列,还有一个样例?咦怎么过不去? 纠结了一会发现——读错题了,啪啪啪,全写错了……立马就凌乱了 赶快做T1,结果发现meet in middle的空间复杂度好像炸