# 【CodeForces - 1080F】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@

就是这样，新的一天里，也请多多关照哦(ノω<。)ノ))☆.。

还能输入1000个字符