@Katya and Segments Sets@
@Desciption@
It is a very important day for Katya. She has a test in a programming class. As always, she was given an interesting problem that she solved very fast. Can you solve that problem?
You are given n ordered segments sets. Each segment can be represented as a pair of two integers [l,r] where l≤r. Each set can contain an arbitrary number of segments (even 0). It is possible that some segments are equal.
You are also given m queries, each of them can be represented as four numbers: a,b,x,y. For each segment, find out whether it is true that each set p (a≤p≤b) contains at least one segment [l,r] that lies entirely on the segment [x,y], that is x≤l≤r≤y.
Find out the answer to each query.
Note that you need to solve this problem online. That is, you will get a new query only after you print the answer for the previous query.
Input
The first line contains three integers n, m, and k (1≤n,m≤105,1≤k≤3⋅105) — the number of sets, queries, and segments respectively.
Each of the next k lines contains three integers l, r, and p (1≤l≤r≤109,1≤p≤n) — the limits of the segment and the index of a set, to which this segment belongs.
Each of the next m lines contains four integers a,b,x,y (1≤a≤b≤n,1≤x≤y≤109) — the description of the query.
Output
For each query, print “yes” or “no” in a new line.
Example
input
5 5 9
3 6 3
1 3 1
2 4 2
1 2 3
4 6 5
2 5 3
7 9 4
2 3 1
4 10 4
1 2 2 3
1 2 2 4
1 3 1 5
2 3 3 6
2 4 2 9
output
no
yes
yes
no
yes
Note
For the first query, the answer is negative since the second set does not contain a segment that lies on the segment [2,3].
In the second query, the first set contains [2,3], and the second set contains [2,4].
In the third query, the first set contains [2,3], the second set contains [2,4], and the third set contains [2,5].
In the fourth query, the second set does not contain a segment that lies on the segment [3,6].
In the fifth query, the second set contains [2,4], the third set contains [2,5], and the fourth contains [7,9].
@Translation@
给定 k 条线段,每一条线段属于 1~n 中的某一个集合。
m 次询问,每次询问形如 (a, b, x, y),即询问是否集合 a~b 中,都存在一条线段被线段[x, y]覆盖。
k <= 3*105;n, m<=105。
@Solution@
对于这种题当然是先考虑暴力,再考虑用数据结构优化。
有两种思维方向,一种是从线段为元素出发,查询[x, y]内的线段是否能将[a, b]这些集合囊括入内;一种是从集合为元素出发,查询[a, b]这个区间的集合是否都有线段在[x, y]之间。
第二个一定会比第一个好做,不然题目给你[a, b]这个区间是白给的吗-_-。
考虑对于某一个集合,它包含某一条线段[l, r]在[x, y]之间,相当于满足 r <= y 的线段中最大的 l >= x。
相当于我们在满足 r <= y 的前提下,求出[a, b]集合中的线段最大的 l,将这些 l 取最小值 lmin。如果 lmin >= x,则有解,输出 yes;否则输出 no。
在满足 r <= y 的前提下,我们可以用可持久化线段树来搞。按照 r 从小到大的顺序,将 l 依次加入线段树并维护历史版本。这样就可以取得任意的 r <= y 情况下的线段树。就可以进行相应的询问。
@Code@
这一场 CF 的题目质量还算不错吧。有考算法,考思维推结论,还有考(简单的)数据结构。
不过当时看都没来得及看这道题……
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
const int MAXK = 300000;
const int INF = (1<<30);
struct Segment{
int l, r, p;
Segment(int _l=0, int _r=0, int _p=0):l(_l), r(_r), p(_p){}
}seg[MAXK + 5];
bool operator < (Segment a, Segment b) {
return a.r < b.r;
}
struct SegmentTree{
SegmentTree *ch[2]; int mn;
}tree[MAXK*20 + 5], *root[MAXK + 5], *NIL, *tcnt;
void init() {
NIL = tcnt = &tree[0];
NIL->ch[0] = NIL->ch[1] = NIL;
NIL->mn = -INF;
}
void insert(SegmentTree *rt1, SegmentTree *&rt2, int pos, int key, int le, int ri) {
rt2 = (++tcnt); *(rt2) = *(rt1);
if( le == ri ) rt2->mn = max(rt2->mn, key);
else {
int mid = (le + ri) >> 1;
if( pos <= mid )
insert(rt1->ch[0], rt2->ch[0], pos, key, le, mid);
else insert(rt1->ch[1], rt2->ch[1], pos, key, mid+1, ri);
rt2->mn = min(rt2->ch[0]->mn, rt2->ch[1]->mn);
}
}
int query(SegmentTree *rt, int le, int ri, int ql, int qr) {
if( ql > ri || qr < le )
return INF;
else if( ql <= le && ri <= qr )
return rt->mn;
int mid = (le + ri) >> 1;
return min(query(rt->ch[0], le, mid, ql, qr), query(rt->ch[1], mid+1, ri, ql, qr));
}
int main() {
init(); int n, m, k;
scanf("%d%d%d", &n, &m, &k);
for(int i=1;i<=k;i++)
scanf("%d%d%d", &seg[i].l, &seg[i].r, &seg[i].p);
sort(seg+1, seg+k+1); root[0] = NIL;
for(int i=1;i<=k;i++)
insert(root[i-1], root[i], seg[i].p, seg[i].l, 1, n);
for(int i=1;i<=m;i++) {
int a, b, x, y;
scanf("%d%d%d%d", &a, &b, &x, &y);
int p = upper_bound(seg+1, seg+k+1, Segment(0, y, 0)) - seg - 1;
int q = query(root[p], 1, n, a, b);
if( q >= x ) puts(q >= x ? "yes" : "no");
fflush(stdout);
}
}
@End@
就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。