[BJOI2016]回轉壽司
阿新 • • 發佈:2020-08-03
似乎沒有人打平衡樹的題解,那我就來水一發~
我們將題目做一個簡單的轉化:
設\(sum_i = \sum_{j=1}^{i} a_j\)
那麼答案就是\(\sum_{i=1}^{n}\sum_{j=1}^{i} (L \leq (sum_i - sum_{j-1}) \leq R)\)
我們可以利用容斥的思想進行簡單是轉化:
\(\sum_{i=1}^{n}\sum_{j=1}^{i} (L \leq (sum_i - sum_{j-1})) - \sum_{i=1}^{n}\sum_{j=1}^{i} (R < (sum_i - sum_{j-1}))\)
因此,我們只用列舉\(sum_i\)
而查詢這些數目完全可以用平衡樹來實現,下面的程式碼打的是\(treap\),僅供參考。
注:題目的資料範圍似乎有問題,似乎是\(0 \leq L , R\leq 10^9\)
#include <cstdio> #include <ctime> #include <algorithm> using namespace std; typedef long long LL; const int MAXN = 1e5 + 5; struct node { LL lc , rc , data , pri , si , cnt; }t[MAXN]; void Zig(LL &k) { LL y = t[k].lc; t[k].lc = t[y].rc; t[y].rc = k; t[y].si = t[k].si; t[k].si = t[t[k].lc].si + t[t[k].rc].si + t[k].cnt; k = y; } void Zag(LL &k) { LL y = t[k].rc; t[k].rc = t[y].lc; t[y].lc = k; t[y].si = t[k].si; t[k].si = t[t[k].lc].si + t[t[k].rc].si + t[k].cnt; k = y; } LL num = 0; void Insert(LL &k , LL key) { if(!k) { k = ++num; t[k].data = key;t[k].pri = rand(); t[k].si = 1;t[k].cnt = 1; return; } t[k].si ++; if(t[k].data == key) t[k].cnt ++; else if(t[k].data < key) { Insert(t[k].rc , key); if(t[t[k].rc].pri < t[k].pri) Zag(k); } else { Insert(t[k].lc , key); if(t[t[k].lc].pri < t[k].pri) Zig(k); } } LL n , rt; LL x_rank(LL x) { LL k = rt , ans = 0; while(k) { if(x == t[k].data) return ans + t[t[k].lc].si + t[k].cnt; if(x > t[k].data) ans += t[t[k].lc].si + t[k].cnt , k = t[k].rc; else k = t[k].lc; } return ans; } LL L , R , a[MAXN]; int main() { srand(19491001); scanf("%lld %lld %lld" , &n , &L , &R); for (int i = 1; i <= n; ++i) { scanf("%lld" , &a[i]); a[i] += a[i - 1]; } LL ans = 0; Insert(rt , 0); for (int i = 1; i <= n; ++i) { ans += x_rank(a[i] - L); ans -= x_rank(a[i] - R - 1); Insert(rt , a[i]); } printf("%lld" , ans); return 0; }