【USACO 2021 February Contest, Platinum】Problem 1 No Time to Dry
阿新 • • 發佈:2021-08-16
\(\text{Solution}\)
一個點可與另一個顏色相同點同時塗色當且僅當兩點間顏色都大於等於這兩點
那麼我們可以預處理一個點向左向右最遠能到的位置,記為 \(l_i,r_i)\)
當 \(l_i = l_j \text{ and }r_i = r_j\) 時,\((i,j)\) 就可以同時塗色
我們認為他們是相同
預處理 \(l_i,r_i\) 正反兩次單調棧即可
那麼一個區間的答案就是 \(l_i,r_i\) 不相同的個數
將 \(l_i,r_i\) 排序後重新編號,主席樹維護即可
這就相當於區間數顏色
注:空間開到 \(2 \log n\) 倍
紀念考場暴切此題但空間開小白丟 \(5pts\)
#include <cstdio> #include <algorithm> #include <cstring> #define re register using namespace std; const int N = 2e5 + 5; int n, q, stk[N], top; struct node{int v, l, r, id;}a[N]; inline void read(int &x) { x = 0; char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); } inline bool cmp1(node a, node b){return (a.l < b.l ? 1 : (a.l == b.l ? a.r < b.r : 0));} inline bool cmp2(node a, node b){return a.id < b.id;} int size, lst[N], rt[N]; struct ChairManTree{int ls, rs, s;}seg[N * 40]; inline void update(int &p, int pre, int l, int r, int x, int v) { p = ++size; seg[p] = seg[pre], seg[p].s = seg[pre].s + v; if (l == r) return; int mid = (l + r) >> 1; if (x <= mid) update(seg[p].ls, seg[pre].ls, l, mid, x, v); else update(seg[p].rs, seg[pre].rs, mid + 1, r, x, v); } inline int query(int p, int l, int r, int x) { if (l == r) return seg[p].s; int mid = (l + r) >> 1; if (x <= mid) return query(seg[p].ls, l, mid, x) + seg[seg[p].rs].s; return query(seg[p].rs, mid + 1, r, x); } int main() { read(n), read(q); for(re int i = 1; i <= n; i++) read(a[i].v), a[i].l = a[i].r = a[i].id = i; for(re int i = 1; i <= n; i++) { while (top && a[stk[top]].v >= a[i].v) a[i].l = a[stk[top]].l, --top; if (!top) a[i].l = 1; stk[++top] = i; } top = 0; for(re int i = n; i; i--) { while (top && a[stk[top]].v >= a[i].v) a[i].r = a[stk[top]].r, --top; if (!top) a[i].r = n; stk[++top] = i; } sort(a + 1, a + n + 1, cmp1); a[1].v = top = 1; for(re int i = 2; i <= n; i++) if (a[i].l == a[i - 1].l && a[i].r == a[i - 1].r) a[i].v = top; else a[i].v = ++top; sort(a + 1, a + n + 1, cmp2); memset(lst , 255 , sizeof lst); for(re int i = 1, pre; i <= n; i++) { if (lst[a[i].v] == -1) update(rt[i], rt[i - 1], 1, n, i, 1); else update(pre, rt[i - 1], 1, n, lst[a[i].v], -1), update(rt[i], pre, 1, n, i, 1); lst[a[i].v] = i; } for(re int i = 1, l, r; i <= q; i++) read(l), read(r), printf("%d\n", query(rt[r], 1, n, l)); }