题目上说每两条线段要么没有公共点,要么完全覆盖,而且又规定了输入顺序,因此对于某个点来说后输入的长度一定短,所以用线段树做区间更新即可。
由于数字很大,需要先做一个离散化,把线段的点和询问的点离散后更新线段树。
#include <cstdio>
#include <map>
using namespace std;
#define lchild rt << 1, l, m
#define rchild rt << 1 | 1, m + 1, r
const int maxn = 1e5 + 5;
const int sz = 2 * maxn * 4;
struct edge {
int u, v;
};
int tree[sz];
edge e[maxn];
int q[maxn];
int n;
void push_up(int rt) {
if (tree[rt<<1] == tree[rt<<1|1]) {
tree[rt] = tree[rt<<1];
} else {
tree[rt] = -1;
}
}
void push_down(int rt) {
tree[rt<<1|1] = tree[rt<<1] = tree[rt];
}
void build(int rt = 1, int l = 1, int r = n) {
tree[rt] = -1;
if (l == r) {
return;
}
int m = (l + r) >> 1;
build(lchild);
build(rchild);
}
void update(int i, int L, int R, int rt = 1, int l = 1, int r = n) {
if (L <= l && r <= R) {
tree[rt] = i;
return;
}
if (tree[rt] > 0)
push_down(rt);
int m = (l + r) >> 1;
if (L <= m) {
update(i, L, R, lchild);
}
if (R > m) {
update(i, L, R, rchild);
}
push_up(rt);
}
int query(int p, int rt = 1, int l = 1, int r = n) {
if (l == r) {
return tree[rt];
}
if (tree[rt] > 0)
push_down(rt);
int m = (l + r) >> 1;
if (p <= m) {
return query(p, lchild);
} else {
return query(p, rchild);
}
}
map<int, int> mp;
int main(int argc, char const *argv[]) {
int k, m;
scanf("%d", &k);
for (int i = 0; i < k; i++) {
scanf("%d%d", &e[i].u, &e[i].v);
mp[e[i].u] = 0;
mp[e[i].v] = 0;
}
scanf("%d", &m);
for (int i = 0; i < m; i++) {
scanf("%d", &q[i]);
mp[q[i]] = 0;
}
map<int, int>::iterator it;
int cnt = 1;
for (it = mp.begin(); it != mp.end(); it++) {
it->second = cnt++;
}
n = mp.size();
build();
for (int i = 0; i < k; i++) {
update(i+1, mp[e[i].u], mp[e[i].v]);
}
for (int i = 0; i < m; i++) {
printf("%d\n", query(mp[q[i]]));
}
return 0;
}