P2234營業額統計(Splay)
阿新 • • 發佈:2021-12-07
傳送門:營業額統計
Splay 練手題,對於營業額維護 Splay。考慮當前節點對於答案的貢獻,直接尋找前驅後繼並判斷誰更近即可,直接累計到答案中。(注意判斷是否存在前驅和後繼)
#include<bits/stdc++.h> using namespace std; const int N = 100000 + 10; const int inf = 1 << 29; int n,root,res,tot; int a[N],val[N],fa[N],siz[N],cnt[N],ch[N][2]; int create(int v,int ff) { val[++tot] = v,fa[tot] = ff; siz[tot] = cnt[tot] = 1; return tot; } void maintain(int x) { siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + cnt[x]; } int getwhich(int x) { return x == ch[fa[x]][1]; } void rotate(int x) { int ff = fa[x],gf = fa[ff]; int k = getwhich(x),tmp = ch[x][k ^ 1]; fa[tmp] = ff,ch[ff][k] = tmp; fa[x] = gf; if(gf) ch[gf][getwhich(ff)] = x; fa[ff] = x,ch[x][k ^ 1] = ff; maintain(x),maintain(ff); } void splay(int x) { for(int ff = fa[x];ff = fa[x];rotate(x)) if(fa[ff]) rotate(getwhich(x) == getwhich(ff) ? ff : x); root = x; } void ins(int v) { if(not root) { root = create(v,0); return; } int cur = root,ff = 0; while(1) { if(val[cur] == v) { cnt[cur]++; maintain(cur),maintain(ff); splay(cur); break; } ff = cur; cur = ch[cur][val[cur] < v]; if(not cur) { ch[ff][val[ff] < v] = create(v,ff); maintain(ff); splay(tot); break; } } } int rankle(int v) { int cur = root,ans = 0; while(1) { if(not cur) return ans + 1; if(v < val[cur]) cur = ch[cur][0]; else if(v == val[cur]) { ans += siz[ch[cur][0]]; splay(cur); return ans + 1; } else { ans += siz[ch[cur][0]] + cnt[cur]; cur = ch[cur][1]; } } } int charge() { int cur = ch[root][0]; while(ch[cur][1]) cur = ch[cur][1]; return cur; } int recoil() { int cur = ch[root][1]; while(ch[cur][0]) cur = ch[cur][0]; return cur; } void reliese(int v) { rankle(v); if(cnt[root] > 1) { cnt[root]--; maintain(root); return ; } else if(not ch[root][0] and not ch[root][1]) { root = 0; return ; } else if(not ch[root][0]) { root = ch[root][1]; fa[root] = 0; return ; } else if(not ch[root][1]) { root = ch[root][0]; fa[root] = 0; return ; } int tmp = ch[root][1],pre = charge(); splay(pre); fa[tmp] = root; ch[root][1] = tmp; maintain(root); } signed int main() { scanf("%d",&n); for(int i = 1;i <= n;i++) scanf("%d",&a[i]); res = a[1]; ins(a[1]); for(int i = 2;i <= n;i++) { ins(a[i]); rankle(a[i]); //cout << rankle(a[i]) << endl; if(cnt[root] > 1) continue; //cout << rankle(a[i]) << endl; int mn = inf,mnn = inf; //rankle(a[i]); if(charge() != 0) mn = val[charge()]; if(recoil() != 0) mnn = val[recoil()]; if(charge() != 0 or recoil() != 0) res += min(abs(a[i] - mn),abs(a[i] - mnn)); //cout << res << endl; } //cout << cnt[rankle(5)] << endl; printf("%d\n",res); return 0; }