F. Monkeying Around 维护点在多少个线段上

Posted stupid_one

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了F. Monkeying Around 维护点在多少个线段上相关的知识,希望对你有一定的参考价值。

http://codeforces.com/gym/101350/problem/F

题意:有m个笑话,每个笑话的区间是[L, R],笑话种类有1e5,一开始所有猴子都在凳子上,听到一个笑话,就倒下,但是如果是听过的笑话,就重新回到凳子上。问最终有多少个猴子在凳子上。

相当于有1e5个线段,如果我们能知道第i个猴子,被多少个线段覆盖了,那么可以找出那些线段中的最后那一条,就是最后覆盖上去的那一条,那条线段是哪一个笑话,设为k,如果这个笑话覆盖这个猴子的次数 > 1,那么这个猴子将会回到凳子上。也就是只和最后一步有关

那么,假如有线段:

按左端点排序:[1, 100], [2, 2]  ,一个扫描变量p1 = 1开始

按右端点排序:[2, 2],  [1, 100], 一个扫描变量p2 = 1开始

就能很快判断到第i个猴子被那些线段覆盖了。

按顺序枚举每一个猴子i,比如i = 2

那么,把i >= segment1[p1].L的都表明这条线段能覆盖i

吧i > segment2[p2].R的都表明这条线段已经离开了i

然后统计即可。

技术分享
#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 2e5 + 20;
struct Node {
    int L, R, id;
}one[maxn], two[maxn];
bool cmp1(struct Node a, struct Node b) {
    return a.L < b.L;
}
bool cmp2(struct Node a, struct Node b) {
    return a.R < b.R;
}
int idForJoke[maxn];
int has[maxn];
set<int>ss;
void work() {
    ss.clear();
    memset(has, 0, sizeof has);
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) {
        int pos, joke, dis;
        scanf("%d%d%d", &pos, &joke, &dis);
        one[i].L = max(1, pos - dis), one[i].R = min(n, pos + dis), one[i].id = i;
        two[i] = one[i];
        idForJoke[i] = joke;
    }
    sort(one + 1, one + 1 + m, cmp1);
    sort(two + 1, two + 1 + m, cmp2);
    int ans = 0, p1 = 1, p2 = 1;
    for (int i = 1; i <= n; ++i) {
        while (p1 <= m && i >= one[p1].L) {
            ss.insert(one[p1].id);
            has[idForJoke[one[p1].id]]++;
            ++p1;
        }
        while (p2 <= m && i > two[p2].R) {
            ss.erase(two[p2].id);
            has[idForJoke[two[p2].id]]--;
            ++p2;
        }
        if (ss.size()) {
            ans += has[idForJoke[*ss.rbegin()]] > 1;
        } else ans++;
    }
    printf("%d\n", ans);
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    int t;
    scanf("%d", &t);
    while (t--) work();
    return 0;
}
View Code

 

以上是关于F. Monkeying Around 维护点在多少个线段上的主要内容,如果未能解决你的问题,请参考以下文章

teamD1第一场 GYM 101350 F. Monkeying Around

Codeforces915 F. Imbalance Value of a Tree(思维+并查集)

Codeforces Round #638 (Div. 2) F. Phoenix and Memory 区间贪心+线段树

Codeforces1539 F. Strange Array(思维,线段树)

codeforces round 512 F. Putting Boxes Together 树状数组维护区间加权平均数

Comet OJ - Contest #8 F.黄金体验 LCT 维护长链剖分+线段树