CodeForces-1175E Minimal Segment Cover

题目描述

现有\(n\)条线段,每条线段的左右端点为\(L_i,R_i\),保证\(L_i \le R_i\).

有\(m\)个询问,每次查询\(X_i,Y_i\)区间内所有点被覆盖所需的线段的最小值。

Input

输入第一行包含两个整数\(n,m\),含义如上所述。

接下来,有\(n\)行,每行有两个整数。

第\(i+1\)行包含\(2\)个整数,分别表示\(L_i,R_i\) 。

接下来\(m\)行,表示\(m\)个询问。

\(1 \le n,m \le 2e5\)

\(0 \le L_i \le R_i \le 5e5\)

\(0 \le X_i \le Y_i \le 5e5\)

Output

对于每个询问输出一个答案。

若无法覆盖,输出\(-1\)即可。

Sample Input

2 3
1 3
2 4
1 3
1 4
3 4
3 4
1 3
1 3
4 5
1 2
1 3
1 4
1 5

Sample Output

1
2
1
1
1
-1
-1

利用倍增维护线段覆盖到的区间。

首先,我们发现对于一个端点我们只用关心能覆盖它的线段最远能覆盖到哪里。

对于每个左端点处理出用同一条线段最远的右端点。

那么,覆盖的过程就是从左端点跳到最远的点,\(Ans++\),重复执行这个过程直到覆盖到右端点。

如果暴力模拟,每次从一个段点跳到另一个端点,时间复杂度\(O(n)\)。

仔细想想,我们发现这个过程和\(LCA\)的过程很像,于是我们就可以用倍增维护了。

\(Fa[i][j]\) 表示用\(1<<j\)条线段,从\(i\)开始最远能覆盖到的点。

代码如下

#include <cstdio>
#include <cstring>
#include <map>
#include <queue>
#include <iostream>
#include <algorithm>

using namespace std;

#define int long long
#define u64 unsigned long long
#define Raed Read
#define reg register
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(reg int i=(G).Head[x]; i; i=(G).Nxt[i])

inline int Read() {
    int res = 0, f = 1;
    char c;
    while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
    do res = (res << 3) + (res << 1) + (c ^ 48);
    while (c = getchar(), c >= 48 && c <= 57);
    return f ? res : -res;
}

template<class T>inline bool Min(T &a, T const&b) {
    return a > b ? a = b, 1 : 0;
}
template<class T>inline bool Max(T &a, T const&b) {
    return a < b ? a = b, 1 : 0;
}

const int N = 2e5 + 5, M = 5e5 + 5, mod = 1e6 + 7;
const int dx[5] = {1, -1, 0, 0, 0}, dy[5] = {0, 0, 0, 1, -1};
const  double eps = 1e-6;

int Fa[M][20], R[M];

inline void _main(void) {
    int n = Read(), m = Raed();
    rep(i, 1, n) {
        int x = Raed(), y = Read();
        Max(R[x], y);
    }
    Fa[0][0] = R[0];
    rep(i, 1, M - 5)Max(R[i], R[i - 1]), Fa[i][0] = R[i];
    rep(j, 1, 19)rep(i, 0, M - 5)Fa[i][j] = Fa[Fa[i][j - 1]][j - 1];
    while (m--) {
        int Ans = 0, l = Raed(), r = Raed();
        drep(i, 19, 0)if (Fa[l][i] < r)l = Fa[l][i], Ans |= 1 << i;
        l = Fa[l][0];
        if (l < r)Ans = -1;
        else Ans++;
        printf("%d\n", Ans);
    }
}

signed main() {
#define offline1
#ifdef offline
    freopen(".in", "r", stdin);
    freopen(".out", "w", stdout);
    _main();
    fclose(stdin); fclose(stdout);
#else
    _main();
#endif
    return 0;
}

原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11259557.html

时间: 2024-10-05 23:25:26

CodeForces-1175E Minimal Segment Cover的相关文章

codeforce 1175E Minimal Segment Cover ST表 倍增思想

这题太巧妙了. 题意是,给定2*10^5个区间.然后2*10^5组询问,每次询问一个区间,问至少需要几个给定区间,才能将其完全覆盖.坐标范围5*10^5. 如果只有一个询问区间,是经典的贪心问题.我们每次选择,尽可能覆盖的靠右的区间. 但是这题显然贪心的话,时间是不够的. 考虑使用倍增进行预处理. 我们用dp[i][o]表示从i点开始,选择o个区间,能覆盖到最远哪个点.为-1,则表示不存在. 那么显然如果dp[i][o - 1] != -1 时,dp[i][o] = dp[dp[i][o - 1

CF1175E Minimal Segment Cover

题目链接 题意 给出n条线段.m次询问,每次询问给出一个区间\([l,r]\)问最少需要多少条线段才能覆盖区间\([l,r]\). 所有坐标\(\le 5\times 10^5\).\(n,m\le 2\times 10^ 5\) 思路 其实是比较经典的线段覆盖问题. \(f[i][j]\)表示从i开始走\(2^j\)条线段最远到达的位置. 然后对于每次询问都走一遍即可. 代码 /* * @Author: wxyww * @Date: 2019-06-06 10:55:48 * @Last Mo

CF1175E Minimal Segment Cover 题解

题意:给出\(n\)个形如\([l,r]\)的线段.\(m\)次询问,每次询问区间\([x,y]\),问至少选出几条线段,使得区间\([x,y]\)的任何一个部位都被至少一条线段覆盖. 首先有一个显然的贪心,设询问区间为\([l,r]\),则所取的区间最靠左的一个的左端点必定小于等于\(l\),并且要使这个区间尽可能地向右延伸. 取完第一个之后,重复以上的贪心,直至满足条件,那么这样的答案必定是最小的. 但是这样的时间复杂度是\(O(nm)\)的,所以要考虑优化,优化方法是用倍增,每次向右跳\(

codeforces 397A On Segment&#39;s Own Points-yy

题意:有很多区间,找出目标区间不跟任何其他区间重叠的部分的长度 分析: 觉得很简单的题,但是脑子没转过弯了,一直没对. 思路就是用一个vis[]数组记录这个点是否被其他区间用了,但是不知道怎么了,我一直固执的要记录两个端点,结果,当然怎么都不对,因为要求的是区间的长度,跟点的个数不是一致的,而且最致命的就是这种方法会错过这样的区间:比如被别人占有的区间是(1,2),(3,4)  则目标区间还能用(2,3),但是如果记录了两个端点,那么会漏掉这个情况.然后我就一直卡在这了.其实只要记录区间的一个端

Codeforces 797C -Minimal string

Petya recieved a gift of a string s with length up to 105 characters for his birthday. He took two more empty strings t and u and decided to play a game. This game has two possible moves: Extract the first character of s and append t with this charac

Codeforces 825E Minimal Labels - 拓扑排序 - 贪心

You are given a directed acyclic graph with n vertices and m edges. There are no self-loops or multiple edges between any pair of vertices. Graph can be disconnected. You should assign labels to all vertices in such a way that: Labels form a valid pe

CodeForces - 1073E :Segment Sum (数位DP)

You are given two integers l l and r r (l≤r l≤r ). Your task is to calculate the sum of numbers from l l to r r (including l l and r r ) such that each number contains at most k k different digits, and print this sum modulo 998244353 998244353 . For

codeforces gym 100345I Segment Transformations [想法题]

题意简述 给定一个由A C G T四个字母组成的密码锁(每拨动一次 A变C C变G G变T T变A) 密码锁有n位 规定每次操作可以选取连续的一段拨动1~3次 问最少几次操作可以将初始状态变到末状态 并且把每次操作输出 (此题有spj) --------------------------------------------------------------------------------------------------------- 为了方便叙述 所有没有明确说明的位置均是在mod4

CodeForces - 976F Minimal k-covering

Description 给你一张左边 \(n_1\) 个点,右边 \(n_2\) 个点, \(m\) 条边的二分图.对于每一个 \(0\le k\le minDeg\) ,求选取哪些边可以使每个点的度数都不小于 \(k\) . \(1\le n_1,n_2\le 2000\) , \(m\le 2000\) Solution 大力建模谁都会系列,多组询问会炸. 于是建边就建流量为 \(deg[i]-k\) 的边,每次增加流量即可. #include<bits/stdc++.h> using n