题目大意
定义区间
(a,b)
能走到区间
(c,d)
的条件是
c<a<d
或
c<b<d
。
现在有两种操作:
Ord=1:
新加入一个区间
(a,b)
(后加入的区间保证比新加入的区间长)
Ord=2
:询问从第
a
个区间能否走到第
现在有
M
个操作,对于第二个操作输出
M≤105
a,b≤109
解题思路
首先我们先考虑两个区间连边的情况,如果不是包含关系,那么这两个区间连的就是双向边,如果是包含关系,那么就是小的区间向大的区间连一条单向边。
我们先讨论双向边的情况,因为是双向边,所以我们能采用并查集维护联通块的思想。如果有两个能互相到达的区间,那么我们就把它们合并成一个区间,具体的实现可以用线段树维护。每次加入一个区间可以在线段树中询问这个区间的左右端点是否在别的区间上。对于线段树的一个节点维护覆盖到这里的区间,当一个端点访问到线段树的一个节点时,就把那些区间合并到当前区间,并把那个节点的的标记赋值为当前区间。其实就是实现了一个区间的并查集的功能。
而对于最后的询问只需看一下两个区间是否在同一个并查集。当然如果是覆盖的情况(单向边)也要考虑进去。
程序
具体实现可以看代码。
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int MAXN = 2e5 + 5;
struct Query {
int Ord, x, y;
} Q[MAXN];
vector<int> Tr[MAXN * 4];
map<int,int> Hash;
vector<int> P;
int N, L[MAXN], R[MAXN], Pre[MAXN], Ask[MAXN];
int Get(int Now) {
if (Pre[Now] == Now) return Now;
Pre[Now] = Get(Pre[Now]);
return Pre[Now];
}
void Modify(int Now, int l, int r, int Side, int Ord) {
if (!Tr[Now].empty()) {
for (int i = 0; i < Tr[Now].size(); i ++) {
int Fa = Get(Tr[Now][i]);
L[Ord] = min(L[Ord], L[Fa]);
R[Ord] = max(R[Ord], R[Fa]);
Pre[Fa] = Ord;
}
Tr[Now].clear();
Tr[Now].push_back(Ord);
}
if (l == r) return;
int Mid = (l + r) >> 1;
if (Side <= Mid) Modify(Now * 2, l, Mid, Side, Ord); else
Modify(Now * 2 + 1, Mid + 1, r, Side, Ord);
}
void Push(int Now, int l, int r, int lx, int rx, int Ord) {
if (lx > rx) return;
if (r < lx || l > rx) return;
if (l >= lx && r <= rx) {
Tr[Now].push_back(Ord);
return;
}
int Mid = (l + r) >> 1;
Push(Now * 2, l, Mid, lx, rx, Ord), Push(Now * 2 + 1, Mid + 1, r, lx, rx, Ord);
}
bool In(int Side, int l, int r) {
return Side < r && Side > l;
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i ++) {
scanf("%d%d%d", &Q[i].Ord, &Q[i].x, &Q[i].y);
if (Q[i].Ord == 1) P.push_back(Q[i].x), P.push_back(Q[i].y);
}
sort(P.begin(), P.end());
unique(P.begin(), P.end());
int Num = 0, Cnt = 0;
int pp = 0;
for (int i = 0; i < P.size(); i ++) Hash[P[i]] = ++ Num;
for (int i = 1; i <= N; i ++) {
if (Q[i].Ord == 1) {
int x = Hash[Q[i].x], y = Hash[Q[i].y];
L[++ Cnt] = x, R[Cnt] = y;
Pre[Cnt] = Cnt, Ask[Cnt] = i;
Modify(1, 1, Num, x, Cnt);
Modify(1, 1, Num, y, Cnt);
Push(1, 1, Num, L[Cnt] + 1, R[Cnt] - 1, Cnt);
} else {
pp ++;
int x = Q[i].x, y = Q[i].y;
int l = Hash[Q[Ask[x]].x], r = Hash[Q[Ask[x]].y];
int fa = Get(y);
if (Get(x) == Get(y) || In(l, L[fa], R[fa]) || In(r, L[fa], R[fa])) printf("YES\n");
else printf("NO\n");
}
}
}