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;
}

时间: 2024-10-16 02:50:34

F. Monkeying Around 维护点在多少个线段上的相关文章

GYM 101350 F. Monkeying Around(线段树 or 思维)

F. Monkeying Around time limit per test 2.0 s memory limit per test 256 MB input standard input output standard output When the monkey professor leaves his class for a short time, all the monkeys go bananas. N monkeys are lined up sitting side by sid

2016 ACM/ICPC亚洲区大连站 F - Detachment 【维护前缀积、前缀和、二分搜索优化】

F - Detachment In a highly developed alien society, the habitats are almost infinite dimensional space. In the history of this planet,there is an old puzzle. You have a line segment with x units' length representing one dimension.The line segment can

teamD1第一场 GYM 101350 F. Monkeying Around

[题目大意] 有n只猴子坐在树上,m个笑话. 给出每个讲这个笑话的猴子的编号,笑话的编号,和笑话的影响半径. 如果一个树上的猴子听了没听过的笑话,会掉到树下.如果听过并且在树下,就会爬到树上. 问最后有多少猴子在树上. [输入] n,m 接下来m行,每行ai, bi, r (猴子编号, 笑话编号, 笑话半径) [输出] 猴子个数. [输入样例] 1 10 7 3 11 0 3 11 2 5 12 1 8 13 2 7 11 2 10 12 1 9 12 0 [输出样例] 3 原文地址:https

cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树

1583. [POJ 3237] 树的维护 ★★★★   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条边的权值改成v. NEGATE a b:将点a到点b路径上所有边的权值变成其相反数. QUERY a b

CodeForces 343D 线段树维护dfs序

给定一棵树,初始时树为空 操作1,往某个结点注水,那么该结点的子树都注满了水 操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了 操作3,询问某个点是否有水 我们将树进行dfs, 生成in[u], 访问结点u的时间戳,out[u],离开结点u的时间戳 每个结点的in值对应在线段树中的区间的一点 那么对于操作1, 只要将区间[in[u],out[u]] 的值都改为1, 但是如果区间[in[u],out[u]] 原先存在为0的点,那么父区间肯定是空的,这个操作不能 改变父区间的状态,所以需要

平衡树维护动态凸包

codeforces70D 有两种操作, 1 x y   将(x,y)加入当前的点集合中. 2 x y  询问(x,y)是否在当前点集形成的凸包内. 即我们要动态的维护凸包,将凸包分为上凸包和下凸包,然后将上凸包关于x轴对称一下, 那么只要维护两个下凸包. 考虑用平衡树(为了让x有序)来维护凸包,插入一个点时,判断是否在下凸包的下方,如果是则插入且不断往两边删点,直到所有的点都满足凸包的定义为止. 如下图,插入点p5时,不断判断p5两边的点是否满足凸包的定义. 明显p2不满足.所有新的凸包是由点

如何表达和维护大型逻辑

合抱之木,生于毫末:九层之台,起于累土:千里之行,始于足下. 让我们暂时撇开平台.框架.技术.设计模式.对象思想.敏捷开发论等. 追问程序本质. 从本质上来说, 程序就是一系列有序执行的指令集合. 如何将指令集合组织成可靠可用可信赖的软件(逻辑之塔), 这是个问题. 程序 = 逻辑 + 控制. what to do + when to do. 从编程角度来说, 开发者应对的就是逻辑, 逻辑的表达.组织和维护. 逻辑是事物自此及彼的可接受的序列.指令是逻辑的具体实现形式. 也就是说: 1.   要

Redis笔记系列(二)——Redis安装部署与维护详解

本文介绍Redis2.8的安装部署和维护方法. Redis在linux上的安装 步骤1: 首先从官网下在redis正式版的压缩包redis-2.8.19.tar.gz http://download.redis.io/releases/redis-2.8.19.tar.gz 步骤2:编译源程序: tar zxvf redis-2.8.19.tar.gz [[email protected] Downloads]$ tar zxvf redis-2.8.19.tar.gz [[email prot

F# 天生就是就异步和并行的料

做模型开发免不了要使用异步和并行计算,尤其在多核CPU的今天,更是如此,F#恰逢其时,天生就具备这种能力,先看一个例子. open System open System.Drawing open System.Windows.Forms open System.Threading let r = Random() let drawCurves (frm : Form) = let x, y = frm.ClientSize.Width, frm.ClientSize.Height let g =