傳送
這題比賽的時候考了原題,顧子哥推了出來一個挺複雜的線段樹,沒想到居然是正解。
咱們枚舉大小爲\(x\)的數,那麼若是在區間\([L, R]\)中,\(x\)符合題目的條件,記\(num[i]\)爲\(1\)到\(i\)中\(x\)的出現次數,那麼有\(\frac{num[R] - num[L - 1]}{R - L + 1} > \frac1{2}\),整理得$$2num[R] - R > 2num[L - 1] - (L - 1)$$
因此咱們令\(b[i] = 2num[i] - i\),就變成了要統計\(b[j] < b[i](j < i)\)的個數了。ios
隨便用什麼數據結構維護,對於大小爲\(x\)的數的統計,大概能達到\(O(n^2logn)\)的複雜度。
但每次從\(1\)到\(n\)掃一遍固然不行,因此咱們想,能不能只遍歷\(x\)出現的位置。c++
記\(i\)爲\(x\)這一次出現的位置,\(nxt[i]\)爲\(x\)下一次出現的位置,那麼咱們要快速的找到全部的\(j\),知足\(b[j] < b[i], j < i, i \in [i, nxt[i] - 1]\).git
對於\((i, nxt[i] - 1]\)中的\(b[i]\),有\(b[i] = b[i - 1] - 1\),那麼要查詢的實際是連續的一段前綴和,即\(sum[b[i]], sum[b[i]-1], \cdots, sum[b[i] - (nxt[i] - i - 1)]\).數據結構
由於還要有修改,遂啓發咱們用線段樹維護前綴和,即每一個節點維護小於等於右端點的全部數的和。ide
那麼上述的詢問就至關於對區間\([b[i] - (nxt[i] - i - 1) - 1, b[i] - 1]\)進行查詢。函數
而修改,若是加入一個數\(t\),由於維護的是前綴和,要對區間\([t, n]\)都加\(1\)。可是如今咱們應該把\([i, nxt[i] - 1]\)的貢獻所有加入線段樹中,即將區間\([b[i], n],[b[i] - 1, n], \cdots, [b[i] - (nxt[i] - i), n]\)所有加\(1\)。ui
稍微想一下,會發現,實際上是將區間\([b[i] - (nxt[i] - i), b[i]]\)加一個首項爲1的等比數列,再將區間\([b[i] + 1, n]\)加\(nxt[i] - i\).因此線段樹要支持區間加和區間加等差數列,以及求區間和。
加等比數列,轉換成絕對下標便可,維護一個一次函數而已。spa
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<vector> #include<queue> #include<assert.h> #include<ctime> using namespace std; //#define int long long #define enter puts("") #define space putchar(' ') #define Mem(a, x) memset(a, x, sizeof(a)) #define In inline #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt) typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db eps = 1e-8; const int maxn = 5e5 + 5; In ll read() { ll ans = 0; char ch = getchar(), las = ' '; while(!isdigit(ch)) las = ch, ch = getchar(); while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar(); if(las == '-') ans = -ans; return ans; } In void write(ll x) { if(x < 0) x = -x, putchar('-'); if(x >= 10) write(x / 10); putchar(x % 10 + '0'); } int n, a[maxn]; int pos[maxn], nxt[maxn]; struct Tree { int l, r; bool cl; ll lzi, lzy, sum; In void Clear() { cl = 1; lzi = lzy = sum = 0; } }t[maxn << 3]; In void build(int L, int R, int now) { t[now].l = L, t[now].r = R; if(L == R) return (void)t[now].Clear(); int mid = (L + R) >> 1; build(L, mid, now << 1), build(mid + 1, R, now << 1 | 1); } In void Change(int now, ll d1, ll d2) { int len = t[now].r - t[now].l + 1; t[now].lzi += d1; t[now].sum += (d1 * (1LL * t[now].l + t[now].r) * len >> 1); t[now].lzy += d2; t[now].sum += d2 * len; } In void pushdown(int now) { if(t[now].cl) t[now << 1].Clear(), t[now << 1 | 1].Clear(), t[now].cl = 0; if(t[now].lzi || t[now].lzy) { Change(now << 1, t[now].lzi, t[now].lzy); Change(now << 1 | 1, t[now].lzi, t[now].lzy); t[now].lzi = t[now].lzy = 0; } } In void update(int L, int R, int now, int d1, int d2) { if(L > R) return; if(t[now].l == L && t[now].r == R) { Change(now, d1, d2); return; } pushdown(now); int mid = (t[now].l + t[now].r) >> 1; if(R <= mid) update(L, R, now << 1, d1, d2); else if(L > mid) update(L, R, now << 1 | 1, d1, d2); else update(L, mid, now << 1, d1, d2), update(mid + 1, R, now << 1 | 1, d1, d2); t[now].sum = t[now << 1].sum + t[now << 1 | 1].sum; } In ll query(int L, int R, int now) { if(t[now].l == L && t[now].r == R) return t[now].sum; pushdown(now); int mid = (t[now].l + t[now].r) >> 1; if(R <= mid) return query(L, R, now << 1); else if(L > mid) return query(L, R, now << 1 | 1); else return query(L, mid, now << 1) + query(mid + 1, R, now << 1 | 1) ; } In ll solve(int p) { nxt[0] = p; int x = 0, num = 0; ll ret = 0; while(x <= n) { if(x > 0) num++; int val = (num << 1) - x, tp = nxt[x] - x - 1; ret += query(val - tp - 1, val - 1, 1); update(val - tp, val, 1, 1, -(val - tp - 1)); update(val + 1, n, 1, 0, tp + 1); x = nxt[x]; } t[1].Clear(); return ret; } int main() { n = read(); int TYPE = read(); for(int i = 1; i <= n; ++i) a[i] = read(), pos[i - 1] = n + 1; for(int i = n; i; --i) nxt[i] = pos[a[i]], pos[a[i]] = i; Mem(pos, 0); //重複利用 build(-n, n, 1); ll ans = 0; for(int i = 1; i <= n; ++i) if(!pos[a[i]]) ans += solve(i), pos[a[i]] = 1; write(ans), enter; return 0; }