luogu4113 [HEOI2012]采花
阿新 • • 發佈:2018-09-09
\n () org clas temp 一個 void 刪除 區間
https://www.luogu.org/problemnew/show/P4113
簡化版題意:求出區間中有幾個數出現了兩次以上
題目要求出現兩次以上,而且出現 10 次對答案只產生 1 的貢獻,可以考慮對數字做一些變化
原數組:1 2 3 2 3 3 1 權值數組:0 0 0 1 1 0 1
對於在區間中出現第二次的數的權值為 1,其余為 0,這樣只需要樹狀數組維護一下區間和就行了
將所有詢問按照 l 排序,將 l 相同的做掉,不相同的可以在樹狀數組上修改,對於一個 l 如果不可能出現在詢問中後,可以將其刪除,令 pre[x] 表示數組下標為 x 的數後一個和它相同的數的數組下標(可能有點繞),我們將 pre[x] 位置上的數 -1, 將 pre[pre[x]] 位置上的數 +1即可
復雜度 n log n
#include <bits/stdc++.h> #define For(i, a, b) for(int i = a; i <= b; i++) using namespace std; typedef unsigned long long ull; typedef long long ll; template <typename _T> inline void read(_T &f) { f = 0; _T fu = 1; char c = getchar(); while(c < '0' || c > '9') {if(c == '-') fu = -1; c = getchar();} while(c >= '0' && c <= '9') {f = (f << 3) + (f << 1) + (c & 15); c = getchar();} f *= fu; } const int N = 2000000 + 10; inline int lowbit(int x) {return x & -x;} int f[N], pre[N], now[N], a[N], Ans[N], cnt[N]; // now 維護數組下標 int n, col, m; void add(int x, int y) { for(int i = x; i <= n; i += lowbit(i)) f[i] += y; } int query(int x) { int ans = 0; for(int i = x; i; i -= lowbit(i)) ans += f[i]; return ans; } void del(int x) { if(pre[x]) add(pre[x], -1); if(pre[x] && pre[pre[x]]) add(pre[pre[x]], 1); } struct ele { int l, r, id; bool operator < (const ele A) const {return l < A.l;} }Q[N]; int main() { read(n); read(col); read(m); for(int i = 1; i <= n; i++) { read(a[i]); if(now[a[i]]) pre[now[a[i]]] = i; if(cnt[a[i]] == 1) add(i, 1); now[a[i]] = i; cnt[a[i]]++; } for(int i = 1; i <= m; i++) { read(Q[i].l); read(Q[i].r); Q[i].id = i; } sort(Q + 1, Q + m + 1); int t = 1; for(int i = 1; i <= m; i++) { while(Q[i].l > t) del(t), t++; Ans[Q[i].id] = query(Q[i].r) - query(Q[i].l - 1); } for(int i = 1; i <= m; i++) printf("%d\n", Ans[i]); return 0; }
luogu4113 [HEOI2012]采花