IOI 2015 Teams 分组

IOI 2015 Teams 分组

\[ made \ by \ Ameiyo \]


贪心做法

对于每组询问, 我们从小到大考虑 K ,那么每次肯定是在 A 小于等于 K 的 $ (A, B) $ 中选取最小的 KB ,因为更大的 B 可能后面会用到。

因此每次直接暴力可以得到 $ O(N * S * \log N) $ 的算法(先按 A 排序,然后维护 B 的值,可以考虑树状数组)。


优化之后的做法

我们转换一下题目,对于可以被 K 选择的 $ (A, B) $ ,因为要满足 $ A \le K $ 且 $ K \le B $ ,所以在坐标系中,点 $ (A, B) $ 就要在点 $ (K, K) $ 的左上方。所以对于某个 K ,满足 $ x \in [0, K] , y \in [K, + \infin) $ 的点是可以被其选择的,注意这些点都是在一个矩形中。

但是我们不能直接用所有满足条件的点,因为可能有的点已经被前面的矩形用过了!

对于当前的矩形,他一定会用掉能选的点中,纵坐标最小的 $ K_i $ 个点,记没被用掉的点中最小的纵坐标是 $ H_i $ (注意这里的 $ H_i $ 是指自己到上个矩形的范围内,因为自己所维护的矩形是这一段)。

(在下图中,虽然 Aj 可选但是没有选择的点中最低的,但是 B 的高度才是 $ H_j $ )

那么对于一个 $ K_j \ge K_i $ 的 $ K_j $ ,如果 $ K_j > H_i $ ,那么由于可以被 $ j $ 使用的点 $ i $ 都没有用过,所以 $ j $ 可以直接使用;但如果 $ k_j \le H_i $ ,那么可能某些点(注意存在和 $ H_i $ 高度相同的点)已经被 $ i $ 用过了,所以就不能直接计数。

但是我们可以维护出 $ i $ 还没有用过的点的数量 $ rem_i $ ,这样由于 $ K_j < H_i $ ,所以 $ rem_i $ 这些点 $ j $ 也是可以直接用的,再加上横坐标在 $ (H_i, H_j] $ 之间的 $ j $ 可以使用的点,就是全部 $ j $ 可以使用的点。

注意到我们处理的 K 是单调不降的,所以可以用一个单调栈维护一个 H 单调递减的序列,每次处理之前,把 H 小于当前高度的矩形都出栈(注意只有小于的可以出栈),然后再通过前面的 rem 以及新的点数来判断是否可行并且维护。

因为这是一个二维平面上的计数问题,所以可以用主席树维护点的数量。

代码

int Rt[N], lson[M], rson[M], val[M], cntNode;
void Insert(int &rt, int pre, int l, int r, int x) {
    rt = ++cntNode;
    lson[rt] = lson[pre], rson[rt] = rson[pre];
    val[rt] = val[pre] + 1;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    if (x <= mid) Insert(lson[rt], lson[pre], l, mid, x);
    else Insert(rson[rt], rson[pre], mid + 1, r, x);
}
int Query(int L, int R, int l, int r, int k) { // (cnt) >= k
    if (l == r) return val[R] - val[L];
    int mid = (l + r) >> 1, sum = val[rson[R]] - val[rson[L]];
    if (k > mid) return Query(rson[L], rson[R], mid + 1, r, k);
    else return sum + Query(lson[L], lson[R], l, mid, k);
}
int Queryk(int L, int R, int l, int r, int k) { // kth
    if (l == r) return l;
    int mid = (l + r) >> 1, sum = val[rson[R]] - val[rson[L]];
    if (k > sum) return Queryk(lson[L], lson[R], l, mid, k - sum);
    else return Queryk(rson[L], rson[R], mid + 1, r, k);
}

int n, m, A[N];
struct NODE {
    int x, y;
    inline int operator < (const NODE &__) const {
        return x < __.x || (x == __.x && y < __.y);
    }
} node[N];

int stk[N], rem[N], high[N], Top;
int main() {
    n = read<int>();
    rep (i, 1, n) node[i].x = read<int>(), node[i].y = read<int>();
    sort(node + 1, node + n + 1);

    int cur = 1;
    rep (i, 1, n) {
        Rt[i] = Rt[i - 1];
        for ( ; cur <= n && node[cur].x == i; ++cur)
            Insert(Rt[i], Rt[i], 1, n, node[cur].y);
    }

    rep (ks, 1, read<int>()) {
        rep (i, 1, m = read<int>()) A[i] = read<int>();
        sort(A + 1, A + m + 1), Top = 0;
        rep (i, 1, m) {
            for ( ; high[Top] < A[i] && Top; --Top) ;
            int tot = rem[Top]
                + Query(Rt[stk[Top]], Rt[A[i]], 1, n, A[i]) - A[i];

            if (tot < 0) { puts("0"); break; }
            else if (i == m) { puts("1"); break; }

            int H = Queryk(Rt[stk[Top]], Rt[A[i]], 1, n, tot - rem[Top]);
            for ( ; H > high[Top] && Top; )
                --Top, H = Queryk(Rt[stk[Top]], Rt[A[i]], 1, n, tot - rem[Top]);

            stk[++Top] = A[i], rem[Top] = tot, high[Top] = H;
        }
    }
    return 0;
}


\[ on \ 2019.12.15 \]

原文地址:https://www.cnblogs.com/Ameiyo/p/12044307.html

时间: 2024-10-17 13:46:14

IOI 2015 Teams 分组的相关文章

BZOJ4369 : [IOI2015]teams分组

将分组计划按照$k$从小到大排序,维护一个单调栈,每个元素为一个矩形,按最底下元素从高到低排列,栈顶最低. 每次加入一个矩形可选区域,维护单调栈,可以往回合并. 然后将所有最低点不满足的矩形取出,合并后放回. 每次考虑栈顶区域,将它取到和下一个矩形底边一致时合并. 可持久化线段树维护,时间复杂度$O((n+s)\log n)$. #include<cstdio> #include<algorithm> const int N=500010,M=200010,P=N*20; int

JS—正则表达式

正则表达式的元字符是包含特殊含义的字符,它们有一些特殊的功能,可以控制匹配模式的方式,反斜杠后的元字符失去其特殊含义. 单个字符和数字 .表示匹配除换行符外的单个字符,两个.就表示匹配两个字符 var pattern1=/g.gle/; alert(pattern1.test('gogle'))//true alert(pattern1.test('g\ngle'))//换行符false alert(pattern1.test('ggle'))//没有匹配false var pattern2=/

正则知识点解读及常用表达式(判断有效数字、手机号邮箱等)

---恢复内容开始--- 1.正则仅仅就是用来处理字符串的:匹配.捕获 匹配:验证当前的字符串是否符合我们的规则(每一个正则都是一个规则) 捕获:在整个字符串当中,把符合规则的字符都依次的获取到--->exec.match.replace 2.正则的组成:元字符.修饰符 元字符: 特殊意义的元字符: \d匹配一个0-9的数字相当于[0-9],和它相反的 \D匹配一个除了0-9的任意字符相当于[] \w匹配一个0-9.a-z.A-Z_ 的数字或字符,相当于[0-9a-zA-Z_]  . \s匹配一

阿尔红军我让我特我问题沃特尔行业

http://www.houzz.com/ideabooks/38419124/thumbs/2015.01.04 http://www.houzz.com/ideabooks/38419135/thumbs/2015.01.04 http://www.houzz.com/ideabooks/38419147/thumbs/2015.01.04 http://www.houzz.com/ideabooks/38419107/thumbs/2015.01.04 http://www.houzz.c

哪敢跟学长这么

不少人面庞上有不由得惊呼出声http://weibo.com/09.16/2015/p/1001603887569338240338http://weibo.com/09.16/2015/p/1001603887569338268443http://weibo.com/09.16/2015/p/1001603887569342462767http://weibo.com/09.16/2015/p/1001603887569342462769http://weibo.com/09.16/2015/

右手缓缓握拢而

火红烈日炸裂的一路冲杀进去吧http://weibo.com/2015/09/16/p/1001603887216807041204http://weibo.com/2015/09/16/p/1001603887216811186273http://weibo.com/2015/09/16/p/1001603887216811186277http://weibo.com/2015/09/16/p/1001603887216811235528http://weibo.com/2015/09/16/

叶轻灵苦笑一声

灵光刚刚收起时灵兵潮流尽数的牧尘准备不错http://weibo.com/2015.09.16/p/1001603887492385369004http://weibo.com/2015.09.16/p/1001603887492389563376http://weibo.com/2015.09.16/p/1001603887492393757752http://weibo.com/2015.09.16/p/1001603887492397975161http://weibo.com/2015.

百度是否会骄傲是罚款撒家乐福

http://www.ebay.com/cln/koyche_0293/-/167468813012/2015.02.10 http://www.ebay.com/cln/x_l0513/-/167468823012/2015.02.10 http://www.ebay.com/cln/lhu9368/-/167461855010/2015.02.10 http://www.ebay.com/cln/lonb759/-/167364514017/2015.02.10 http://www.eba

百度的说法矿石结晶发神经

http://www.ebay.com/cln/zhay285/cars/167540455015/2015.02.09 http://www.ebay.com/cln/j-nen73/cars/167540456015/2015.02.09 http://www.ebay.com/cln/jin.p82/cars/167427490013/2015.02.09 http://www.ebay.com/cln/x-x6813/cars/167540459015/2015.02.09 http:/