Team Rocket (線段樹)
阿新 • • 發佈:2018-12-16
給出n個區間和m個詢問,每次詢問給出一個數,規則是如果這個數位於某一個尚未標記的區間內,就標記這個區間。查詢要求輸出此次標記的區間數目,強制線上。所有查詢結束後要求輸出每個區間被標記的時刻。
將所有的區間按照L升序排序,然後將每個區間作為線段樹的葉子節點,這裡線段樹維護的是區間內R的最大值。
對於炸掉的鐵路,可以直接將R更新為-INF。每次查詢的時候,需要先二分出這個點所能影響到的最左的位置k,之後用這個來進行一些剪枝,如果k大於mid或者位置大於當前的R就不進入,這樣將單次查詢的複雜度壓到了O(logn)。
#include <cstdio> #include <cstring> #include <queue> #include <vector> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 200050; const int INF = 0x3f3f3f3f; const ll mod = 998244353; int t, n, m, cnt, k; int ans[maxn]; ll res, x; struct node { int l, r; int id; node(){} node(int L, int R, int ID) { l = L, r = R, id = ID; } bool operator < (const node &a) const { return l < a.l; } }e[maxn]; struct seg { int val; int id; }tree[maxn << 2]; bool cmp(node a, node b) { return a.l < b.l; } void build(int root, int l, int r) { if(l > r) return; if(l == r) { tree[root].val = e[l].r; tree[root].id = e[l].id; return; } int mid = (l + r) >> 1; build(root*2, l, mid); build(root*2 + 1, mid + 1, r); tree[root].val = max(tree[root*2].val, tree[root*2+1].val); } void query(int root, int l, int r, int num) { if(l > r || tree[root].val < x) return; if(l == r) { res = (res*tree[root].id) % mod; tree[root].val = -INF; cnt++; ans[e[l].id] = num; return; } int mid = (l + r) >> 1; query(root*2, l, mid, num); if(k >= mid + 1) query(root*2 + 1, mid + 1, r, num); tree[root].val = max(tree[root*2].val, tree[root*2 + 1].val); } int main() { scanf("%d", &t); int kase = 0; while(t--) { scanf("%d%d", &n, &m); for(int i = 1;i <= n;i++) { scanf("%d%d", &e[i].l, &e[i].r); e[i].id = i; } memset(ans, 0, sizeof(ans)); sort(e+1, e+n+1); build(1, 1, n); cnt = 0, res = 0; printf("Case #%d:\n", ++kase); for(int i = 1;i <= m;i++) { scanf("%lld", &x); x ^= res; k = upper_bound(e+1, e+n+1, node(x, 0, 0)) - e - 1; cnt = 0, res = 1; if(k > 0) query(1, 1, n, i); if(cnt == 0) res = 0; printf("%d\n", cnt); } for(int i = 1;i <= n;i++) { printf("%d", ans[i]); if(i == n) puts(""); else printf(" "); } } return 0; }