Codeforces Round #668 (Div. 2) Eb
阿新 • • 發佈:2020-09-10
E - Fixed Point Removal
每一個數字,能夠被刪除,當且僅當滿足:\(pos_i-a_i-x<=0\)其中x是他之前已經被刪掉的數字的個數。(因為我們總可以在\(pos_i-a_i-x==0\)的時候,將該數字刪除,所以小於等於0的時候一定滿足。)
令\(a[i]=i-a[i]\)。(這個時候的\(a[i]\)就表示成,若他自己能被刪除的話,需要\(a[i]\)個數字,在他位置之前刪掉。)
1.當\(a[i]<0\),一定不行。
2.當\(a[i]>=0\)的時候,我們首先令\(lf_i\)表示第\(i\)個數字,能被刪除的時候,他前面最多被設定了多少個障礙(即題目輸入\(x\)
考慮\(lf_i\)的轉移,\(lf_i=\sum_{j=1}^{i-1}{lf_j}(lf_j>=L)\)
我們就上述式子考慮離線演算法。
維護\(lf_i\)陣列,需要高效的更新和查詢,我們考慮利用主席樹。在主席書上二分出\(L\)。將\(lf_i\)扔進主席樹中,每一次查詢優先進入右子樹,否則進入左子樹,就能夠求出最大的\(L\),滿足\(a[i]\).
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #include <iomanip> #pragma GCC optimize(2) #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 const int N = 3e5 + 10; int n, q; int a[N]; struct zxs { int ls[N * 40]; int rs[N * 40]; int sum[N * 40]; int root[N]; int tot = 0; void insert(int &o, int pre, int l, int r, int val) { o = ++tot; sum[o] = sum[pre] + 1; ls[o] = ls[pre]; rs[o] = rs[pre]; if (l == r)return; int mid = (l + r) >> 1; if (val <= mid)insert(ls[o], ls[pre], l, mid, val); else insert(rs[o], rs[pre], mid + 1, r, val); } int query(int o, int pre, int l, int r, int k) { if (l == r)return l; int mid = (l + r) >> 1; if (sum[rs[o]] - sum[rs[pre]] >= k)return query(rs[o], rs[pre], mid + 1, r, k); else return query(ls[o], ls[pre], l, mid, k - (sum[rs[o]] - sum[rs[pre]])); } int querysum(int o, int pre, int l, int r, int lf, int rt) { if (lf <= l && r <= rt) { return sum[o] - sum[pre]; } int mid = (l + r) >> 1; int ans = 0; if (lf <= mid)ans = querysum(ls[o], ls[pre], l, mid, lf, rt); if (rt > mid)ans += querysum(rs[o], rs[pre], mid + 1, r, lf, rt); return ans; } }T; vector<pir>vec[N]; int ans[N]; int main() { n = read(), q = read(); upd(i, 1, n) { a[i] = read(); a[i] = i - a[i]; } int x, y; upd(i, 1, q) { x = read(), y = read(); vec[n - y].push_back({ x,i }); } upd(i, 1, n) { if (a[i] >= 0) { int temp; if (T.sum[T.root[i - 1]] < a[i]) { T.root[i] = T.root[i - 1]; goto end; } if (a[i] == 0)temp = i - 1; else temp = T.query(T.root[i - 1], T.root[0], 0, n - 1, a[i]); T.insert(T.root[i], T.root[i - 1], 0, n - 1, temp); } else T.root[i] = T.root[i - 1]; end: for (auto k : vec[i]) { ans[k.second] = T.querysum(T.root[i], T.root[0], 0, n - 1, k.first, n - 1); } } upd(i, 1, q)printf("%d\n", ans[i]); return 0; }