回滾莫隊(不刪除莫隊)
阿新 • • 發佈:2020-11-24
題意:
查詢區間 \([l,r]\) 內一個數乘上它在區間出現次數的最大值
使用莫隊的時候進行增加操作的時候會很簡單,但是在刪除操作的時候不是那麼好維護的時候,可以使用不刪除的莫隊(回滾莫隊)
還是相同的思路,先把詢問排序
然後對於左端點在同一個塊的詢問來說
如圖
如果右端點也在塊內,則暴力計算
否則左端點從下一個塊的左邊開始,右端點單調向右移動。
左端點在塊內反覆進行回滾操作。
這樣就在保證時間複雜度還是 \(O(n\sqrt n)\) 的情況下避免了刪除操作
/* * @Author: zhl * @Date: 2020-11-19 10:38:35 */ #include<bits/stdc++.h> using namespace std; using ll = long long; const int N = 1e5 + 10; int n, m, len, cnt[N], nums[N], w[N], ID[N]; ll ans[N]; struct Query { int id, l, r; bool operator < (const Query& rhs)const { int al = ID[l], bl = ID[rhs.l]; if (al != bl)return al < bl; return r < rhs.r; } }q[N]; void add(int x, ll& res) { cnt[x]++; res = max(res, 1ll * cnt[x] * nums[x]); } int main() { scanf("%d%d", &n, &m); int numID = 0; for (int i = 1; i <= n; i++)scanf("%d", w + i), nums[++numID] = w[i]; sort(nums + 1, nums + 1 + n); numID = unique(nums + 1, nums + 1 + n) - nums - 1; len = sqrt(n); for (int i = 1; i <= n; i++)ID[i] = i / len; for (int i = 1; i <= n; i++)w[i] = lower_bound(nums + 1, nums + 1 + numID, w[i]) - nums; for (int i = 1; i <= m; i++) { scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i; } sort(q + 1, q + 1 + m); for (int x = 1; x <= m;) { int y = x; while (y <= m and ID[q[y].l] == ID[q[x].l]) y++; //塊內暴力 int right = len * ID[q[x].l] + len; //int right = len * ID[q[y].l]; 這樣不對,y不一定比x大 while (x < y and q[x].r <= right - 1) { ll res = 0; for (int i = q[x].l; i <= q[x].r; i++) add(w[i], res); ans[q[x].id] = res; for (int i = q[x].l; i <= q[x].r; i++) cnt[w[i]]--; x++; } //塊外 int l = right, r = right - 1; ll res = 0; while (x < y) { int ql = q[x].l, qr = q[x].r; while (r < qr)add(w[++r], res); ll _res = res; while (l > ql)add(w[--l], res); ans[q[x].id] = res; while (l < right) cnt[w[l++]] --; res = _res; x++; } memset(cnt, 0, sizeof cnt); } for (int i = 1; i <= m; i++)printf("%lld\n", ans[i]); }
給定一個序列,多次詢問一段區間 \([l,r]\),求區間中相同的數的最遠間隔距離。
序列中兩個元素的間隔距離指的是兩個元素下標差的絕對值。
這個說是模板題,其實上一道題更模板。
#include<bits/stdc++.h> using namespace std; const int N = 2e5 + 10; int w[N], ans[N], n, m, nums[N], ID[N], len; int fir[N], last[N]; int mfir[N], mlast[N], mpos[N], mcnt, vis[N], vscnt; struct Query { int id, l, r; bool operator < (const Query& b)const { if (ID[l] != ID[b.l])return ID[l] < ID[b.l]; return r < b.r; } }q[N]; void add(int pos, int val, int& res) { if (!fir[val]) fir[val] = pos; else fir[val] = min(fir[val], pos); if (!last[val])last[val] = pos; else last[val] = max(last[val], pos); res = max(res, last[val] - fir[val]); } int main() { scanf("%d", &n); int numID = 0; for (int i = 1; i <= n; i++)scanf("%d", w + i), nums[++numID] = w[i]; sort(nums + 1, nums + 1 + n); numID = unique(nums + 1, nums + 1 + n) - nums - 1; for (int i = 1; i <= n; i++)w[i] = lower_bound(nums + 1, nums + 1 + numID, w[i]) - nums; len = sqrt(n); for (int i = 1; i <= n; i++)ID[i] = i / len; scanf("%d", &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i; } sort(q + 1, q + 1 + m); for (int x = 1; x <= m;) { int y = x; while (y <= m and ID[q[y].l] == ID[q[x].l])y++; int right = ID[q[x].l] * len + len; while (x < y and q[x].r <= right - 1) { int res = 0, mcnt = 0; vscnt++; for (int i = q[x].l; i <= q[x].r; i++) { if (vis[w[i]] != vscnt) { vis[w[i]] = vscnt; mpos[++mcnt] = w[i]; mfir[mcnt] = fir[w[i]]; mlast[mcnt] = last[w[i]]; } add(i, w[i], res); } ans[q[x].id] = res; for (int i = 1; i <= mcnt; i++) { fir[mpos[i]] = mfir[i]; last[mpos[i]] = mlast[i]; } x++; } int l = right, r = right - 1; int res = 0; while (x < y) { int ql = q[x].l, qr = q[x].r; while (r < qr)r++, add(r, w[r], res); int _res = res; mcnt = 0; vscnt++; while (l > ql) { l--; if (vis[w[l]] != vscnt) { vis[w[l]] = vscnt; mpos[++mcnt] = w[l]; mfir[mcnt] = fir[w[l]]; mlast[mcnt] = last[w[l]]; } add(l, w[l], res); } ans[q[x].id] = res; for (int i = 1; i <= mcnt; i++) { fir[mpos[i]] = mfir[i]; last[mpos[i]] = mlast[i]; } l = right; res = _res; x++; } memset(fir, 0, sizeof fir); memset(last, 0, sizeof last); } for (int i = 1; i <= m; i++)printf("%d\n", ans[i]); }