離線
扣的都要點一下中間才會跑出來喔
離線是啥?
如何離線?
為什麼要學離線呢
怕打比賽到一半網路被駭客打掉
防範駭客的小技巧
但這麼做同樣會沒網路
所以這更加凸顯了離線演算法的重要性
以上都是唬爛啦哈哈
離線 = !在線
在線
離線
等詢問都問完了再一次回答
一些簡單離線題
扣
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
struct ooo{
int l, r, v, t;
};
int cnt = 0;
array<int, 10004> A;
array<int, 300004> P;
array<int, 1000004> ans;
array<array<int, 2>, 320004> trie;
vector<ooo> Q;
bool cmp(ooo a, ooo b){
return a.r < b.r;
}
void update(int p, int x, int d, int l){
P[p] = l;
if(d < 0) return;
int c = (x >> d) & 1;
if(!trie[p][c]) trie[p][c] = ++cnt;
update(trie[p][c], x, d - 1, l);
}
int query(int p, int x, int d, int l){
if(d < 0) return x;
int c = ((x >> d) & 1) ^ 1;
if(!trie[p][c] || P[trie[p][c]] < l) c ^= 1;
return (c << d) ^ query(trie[p][c], x, d - 1, l);
}
void run(int n){
int p = 0;
for(int i = 0; i <= n; i++){
while(p < Q.size() && Q[p].r == i){
ans[Q[p].t] = query(0, Q[p].v ^ A[i], 30, Q[p].l);
p++;
}
update(0, A[i], 30, i);
}
}
signed main(){
int n, q, a, l, r, v;
cin >> n >> q;
for(int i = 1; i <= n; i++){
cin >> a;
A[i] = a ^ A[i - 1];
}
for(int i = 1; i <= q; i++){
cin >> l >> r >> v;
Q.pb({l, r, v, i});
}
sort(Q.begin(), Q.end(), cmp);
run(n);
for(int i = 1; i <= q; i++) cout << ans[i] << "\n";
return 0;
}
扣
#include <bits/stdc++.h>
#define pb push_back
#define int long long
#define mid ((l + r) >> 1)
#define lc (p << 1)
#define rc ((p << 1) | 1)
using namespace std;
struct ooo{
int l, r, t;
};
array<int, 200004> X, S, ans;
array<int, 800004> seg, hi, tag;
vector<ooo> Q;
bool cmp(ooo a, ooo b){
return a.l > b.l;
}
void pull(int p){
seg[p] = seg[lc] + seg[rc];
hi[p] = max(hi[lc], hi[rc]);
}
void push(int p, int l, int r){
if(!tag[p]) return;
seg[lc] = (mid - l + 1) * tag[p];
seg[rc] = (r - mid) * tag[p];
hi[lc] = hi[rc] = tag[p];
tag[lc] = tag[rc] = tag[p];
tag[p] = 0;
}
int find(int p, int l, int r, int x){
if(l == r) return l;
if(x > hi[p]) return r + 1;
push(p, l, r);
if(x <= hi[lc]) return find(lc, l, mid, x);
else return find(rc, mid + 1, r, x);
}
void update(int p, int l, int r, int ql, int qr, int x){
if(ql > r || qr < l) return;
if(ql <= l && qr >= r){
seg[p] = (r - l + 1) * x;
tag[p] = hi[p] = x;
return;
}
push(p, l, r);
update(lc, l, mid, ql, qr, x);
update(rc, mid + 1, r, ql, qr, x);
pull(p);
}
int query(int p, int l, int r, int ql, int qr){
if(ql > r || qr < l) return 0;
if(ql <= l && qr >= r) return seg[p];
push(p, l, r);
return query(lc, l, mid, ql, qr) + query(rc, mid + 1, r, ql, qr);
}
void run(int n){
int p = 0, r;
for(int i = n; i > 0; i--){
r = find(1, 1, n, X[i]) - 1;
update(1, 1, n, i, r, X[i]);
while(p < Q.size() && Q[p].l == i){
ans[Q[p].t] = query(1, 1, n, i, Q[p].r) - S[Q[p].r] + S[i - 1];
p++;
}
}
}
signed main(){
int n, q, l, r;
cin >> n >> q;
for(int i = 1; i <= n; i++){
cin >> X[i];
S[i] = X[i] + S[i - 1];
}
for(int i = 1; i <= q; i++){
cin >> l >> r;
Q.pb({l, r, i});
}
sort(Q.begin(), Q.end(), cmp);
run(n);
for(int i = 1; i <= q; i++) cout << ans[i] << "\n";
return 0;
}
扣
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define mid ((l + r) >> 1)
using namespace std;
struct edge{
int u, v, l, r;
};
int n, com;
array<int, 100004> DSU;
vector<pair<int, int>> tmp;
stack<vector<pair<int, int>>> chg;
int ehash(int u, int v){
return u * 100001 + v;
}
pair<int, int> dehash(int x){
return {x / 100001, x % 100001};
}
int fnd(int u){
if(DSU[u] == u) return u;
return fnd(DSU[u]);
}
int find(int u){
tmp.pb({u, DSU[u]});
if(DSU[u] == u){
chg.push(tmp);
tmp.clear();
return u;
}
return DSU[u] = find(DSU[u]);
}
void onion(int u, int v){
int U = find(u), V = find(v);
if(U == V) return;
DSU[V] = U;
com--;
}
void roll(){
tmp = chg.top();
chg.pop();
for(auto [u, d] : tmp){
DSU[u] = d;
}
tmp.clear();
}
void run(int l, int r, vector<edge> &E){
int c = com;
vector<edge> D;
for(edge e : E){
if(e.l > r || e.r < l) continue;
if(e.l <= l && e.r >= r) onion(e.u, e.v);
else D.pb(e);
}
if(l == r) cout << com << " ";
else{
run(l, mid, D);
run(mid + 1, r, D);
}
for(edge e : E){
if(e.l <= l && e.r >= r) roll(), roll();
}
com = c;
}
signed main(){
int m, q, t, a, b, p = 0;
vector<edge> E;
map<int, int> M;
cin >> n >> m >> q;
com = n;
for(int i = 1; i <= n; i++) DSU[i] = i;
while(m--){
cin >> a >> b;
if(a > b) swap(a, b);
M[ehash(a, b)] = 0;
}
while(q--){
cin >> t >> a >> b;
if(a > b) swap(a, b);
p++;
if(t == 1) M[ehash(a, b)] = p;
else{
E.pb({a, b, M[ehash(a, b)], p - 1});
M.erase(ehash(a, b));
}
}
for(auto [e, s] : M){
auto [u, v] = dehash(e);
E.pb({u, v, s, p});
}
run(0, p, E);
return 0;
}
是否發現了什麼
離線 = 排序 & 資結
莫隊
拔掉網路線做分塊
在分塊那邊啦
但我時間太多
莫隊在幹嘛
分塊左界
排序右界
掃!
莫隊其實可以修改哦哦哦
把時間當成一個維度
分塊!
把左、右界都分塊
排序時間
掃!
怎麼分塊?
假設每一塊大小都是 \(K\),序列大小為 \(N\),詢問數量為 \(Q\)
總共會有 \(\dfrac{N}{K}\) 塊
因為左右界都要分塊,因此可能性有 \(\dfrac{N^2}{K^2}\) 種
每一筆詢問的左、右界移動次數為 \(K\) 次
每一種分塊可能性都要花 \(Q\) 去掃時間維度
總複雜度 \(O(QK + \dfrac{QN^2}{K^2})\)
怎麼分塊?
砸算幾:
\(QK + \dfrac{QN^2}{K^2} \ge 2\sqrt{QK \times \dfrac{QN^2}{K^2}}\)
\(QK^3 + QN^2 \ge 2QK^2 \sqrt{\dfrac{N^2}{K}}\)
\(\N^2 + K^3 \ge 2\sqrt{N^2K^3}\)
\(N^2 = K^3\) 時最好
\(K = N^\dfrac{2}{3}\)
總複雜度 : \(O(QN^\dfrac{2}{3})\)
是否發現了什麼?
暴力做是 \(O(QN)\)
跟莫隊只差 \(N^\dfrac{1}{3}\)
所以其實暴力壓常可能有機會唬爛過去
蹄墓
扣
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
struct ooo{
int a, b, t;
};
int col = 0, l = 0, r = -1, t, p;
array<int, 140004> C, ans;
array<int, 1000004> S;
array<array<vector<ooo>, 54>, 54> Q;
vector<ooo> R, chg;
void move(int ql, int qr, int qt){
while(l > ql) col += !S[C[--l]]++;
while(r < qr) col += !S[C[++r]]++;
while(l < ql) col -= !--S[C[l++]];
while(r > qr) col -= !--S[C[r--]];
while(t < qt){
t++;
if(p >= R.size() || t < R[p].t) continue;
chg.pb({C[R[p].a], R[p].b, R[p].a});
if(R[p].a >= l && R[p].a <= r){
col -= !--S[C[R[p].a]];
col += !S[R[p].b]++;
}
C[R[p].a] = R[p].b;
p++;
}
}
void roll(){
reverse(chg.begin(), chg.end());
for(auto [a, b, x] : chg){
if(x >= l && x <= r){
col -= !--S[b];
col += !S[a]++;
}
C[x] = a;
}
chg.clear();
}
void MO(vector<ooo> &O){
t = p = 0;
roll();
for(auto [ql, qr, qt] : O){
move(ql, qr, qt);
ans[qt] = col;
}
}
signed main(){
int n, m, a, b, k;
char c;
cin >> n >> m;
k = ceil(pow(n, 2.0 / 3.0));
for(int i = 1; i <= n; i++) cin >> C[i];
for(int i = 1; i <= m; i++){
cin >> c >> a >> b;
if(c == 'Q') Q[a / k][b / k].pb({a, b, i});
else R.pb({a, b, i});
}
for(int i = 0; i <= n / k; i++){
for(int j = i; j <= n / k; j++){
MO(Q[i][j]);
}
}
for(int i = 1; i <= m; i++){
if(ans[i]) cout << ans[i] << "\n";
}
return 0;
}
回滾莫隊
不能有刪除操作的莫隊
每個詢問左邊都從左界那塊的最右端開始往左加
特判
當左右界同一塊的時候會爆炸
獨立出來暴力跑!
複雜度
跟一般莫隊一樣
\(O(N\sqrt{Q})\)
堤睦
扣
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
struct ooo{
int l, r, t;
};
struct op{
int x, ple, pre, f;
};
int l, r, far;
array<int, 200004> A, L, R, ans;
array<vector<ooo>, 200004> Q;
vector<op> chg;
bool cmp(ooo a, ooo b){
return a.r < b.r;
}
void umbrella(vector<pair<int, int>> &S){
int lst = 0, cnt = 0;
for(auto [x, p] : S){
if(x == lst) A[p] = cnt;
else A[p] = ++cnt;
lst = x;
}
}
void fresh(){
far = 0;
for(int &x : L) x = 1e9;
for(int &x : R) x = 0;
}
void move(int ql, int qr){
while(r < qr){
r++;
L[A[r]] = min(L[A[r]], r);
R[A[r]] = max(R[A[r]], r);
far = max(far, R[A[r]] - L[A[r]]);
}
while(l > ql){
l--;
chg.pb({A[l], L[A[l]], R[A[l]], far});
L[A[l]] = min(L[A[l]], l);
R[A[l]] = max(R[A[l]], l);
far = max(far, R[A[l]] - L[A[l]]);
}
}
void roll(){
reverse(chg.begin(), chg.end());
for(auto [x, ple, pre, f] : chg){
l++;
L[x] = ple;
R[x] = pre;
far = f;
}
chg.clear();
}
void MO(vector<ooo> &O){
for(auto [ql, qr, qt] : O){
move(ql, qr);
ans[qt] = far;
roll();
}
}
signed main(){
int n, m, x, ql, qr, k;
vector<pair<int, int>> S;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> x;
S.pb({x, i});
}
sort(S.begin(), S.end());
umbrella(S);
cin >> m;
k = ceil((double)n / (sqrt(m)));
fresh();
for(int i = 1; i <= m; i++){
cin >> ql >> qr;
if(ql / k == qr / k){
l = qr + 1, r = qr;
move(ql, qr);
ans[i] = far;
roll();
}else Q[ql / k].pb({ql, qr, i});
}
for(int i = 0; i <= n / k; i++){
sort(Q[i].begin(), Q[i].end(), cmp);
fresh();
l = min(n + 1, i * k + k);
r = l - 1;
MO(Q[i]);
}
for(int i = 1; i <= m; i++) cout << ans[i] << "\n";
return 0;
}
整體二分搜
拔掉網路線做二分搜
當你覺得一個一個二分搜太慢的時候就可以全部一起二分搜
只有一筆詢問的作法
戳一個數字,看區間內有幾個數字比他小,然後決定往比較小或大的數字戳
\(O(NlogC)\)
很多筆詢問怎麼辦?
統一戳一個數字,然後決定要把每個詢問往比較小或大那邊丟
加入修改
把改值想成刪除和插入,就可以二分搜了耶
維護序列
砸BIT
複雜度
序列長度為 \(N\),詢問數為 \(Q\)
每筆詢問二分搜時間 \(O(NlogNlogC)\)
全部詢問一起二分搜時間 \(O((Q + N)logNlogC)\)
結論 : \(Q \times N = Q + N\)
\(\times = +\)
扣
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define mid ((l + r) >> 1)
using namespace std;
struct ooo{
int t, l, r, k, p;
};
array<int, 10004> ans;
array<int, 50004> A, BIT;
void update(int p, int v){
for(; p < 50004; p += p & -p) BIT[p] += v;
}
int query(int p){
int sum = 0;
for(; p; p -= p & -p) sum += BIT[p];
return sum;
}
void BIS(int l, int r, vector<ooo> &Q){
if(Q.empty() || l == r){
for(auto [t, ql, qr, k, p] : Q){
if(t) ans[p] = l;
}
return;
}
vector<ooo> L, R;
for(auto [t, ql, qr, k, p] : Q){
if(t){
if(query(qr) - query(ql - 1) >= k) L.pb({t, ql, qr, k, p});
else R.pb({t, ql, qr, k - query(qr) + query(ql - 1), p});
}else{
if(qr <= mid){
update(ql, k);
L.pb({t, ql, qr, k, p});
}else R.pb({t, ql, qr, k, p});
}
}
for(auto [t, ql, qr, k, p] : L){
if(!t) update(ql, -k);
}
BIS(l, mid, L);
BIS(mid + 1, r ,R);
}
signed main(){
int t, n, q, p, l, r, k;
vector<ooo> Q;
cin >> t;
for(int &a : ans) a = 1ll << 31;
while(t--){
Q.clear();
cin >> n >> q;
for(int i = 1; i <= n; i++){
cin >> A[i];
Q.pb({0, i, A[i], 1, 0});
}
for(int i = 1; i <= q; i++){
cin >> p >> l >> r;
if(p == 1){
cin >> k;
Q.pb({1, l, r, k, i});
}else if(p == 2){
Q.pb({0, l, A[l], -1, 0});
Q.pb({0, l, r, 1, 0});
A[l] = r;
}else{
ans[i] = 7122;
}
}
BIS(-(1ll << 31), 1ll << 31, Q);
for(int &a : ans){
if(a < 1ll << 31){
cout << a << "\n";
a = 1ll << 31;
}
}
}
return 0;
}
啼木
扣
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define mid ((l + r) >> 1)
using namespace std;
struct ooo{
int t, l, r, c, p;
};
int pl, pr;
array<int, 100004> pre, V, G, ans, BIT;
array<ooo, 200004> Q, L, R;
bool cmp(ooo a, ooo b){
if(a.l == b.l) return a.t < b.t;
return a.l > b.l;
}
void update(int p, int x){
if(!p) return;
for(; p < 100004; p += p & -p) BIT[p] += x;
}
int query(int p){
int sum = 0;
for(; p; p -= p & -p) sum += BIT[p];
return sum;
}
void BIS(int l, int r, int tl, int tr){
if(Q.empty() || l == r){
for(int i = tl; i <= tr; i++){
auto [t, ql, qr, c, p] = Q[i];
if(!t) ans[c] = l;
}
return;
}
int tmid;
pl = pr = 0;
for(int i = tl; i <= tr; i++){
auto [t, ql, qr, c, p] = Q[i];
if(p > mid) continue;
if(t){
update(qr, c);
update(ql - 1, -c);
}else G[c] += query(100000) - query(qr - 1);
}
for(int i = tl; i <= tr; i++){
auto [t, ql, qr, c, p] = Q[i];
if(t){
if(p <= mid) L[pl++] = {t, ql, qr, c, p};
else R[pr++] = {t, ql, qr, c, p};
}else{
if(G[c] >= V[c]) L[pl++] = {t, ql, qr, c, p};
else{
if(!ql) V[c] -= G[c];
R[pr++] = {t, ql, qr, c, p};
}
if(!ql) G[c] = 0;
}
}
tmid = tl + pl - 1;
for(int i = 0; i < pl; i++){
auto [t, ql, qr, c, p] = L[i];
if(!t) continue;
update(qr, -c);
update(ql - 1, c);
}
for(int i = 0; i < pl; i++){
Q[tl + i] = L[i];
}
for(int i = 0; i < pr; i++){
Q[tmid + i + 1] = R[i];
}
BIS(l, mid, tl, tmid);
BIS(mid + 1, r, tmid + 1, tr);
}
signed main(){
int n, m, q, l, r, c, p = 0;
cin >> n >> m >> q;
for(int i = 1; i <= m; i++){
cin >> c;
Q[p++] = {0, pre[c], i, c, 0};
pre[c] = i;
}
for(int i = 1; i <= n; i++) cin >> V[i];
for(int i = 1; i <= q; i++){
cin >> l >> r >> c;
Q[p++] = {1, l, r, c, i};
}
sort(Q.begin(), Q.begin() + p, cmp);
BIS(1, q + 1, 0, p - 1);
for(int i = 1; i <= n; i++){
cout << (ans[i] <= q && ans[i]? ans[i] : -1) << "\n";
}
return 0;
}
CDQ分治
拔掉網路線做分治
一種分治
一維偏序
排序!
二維偏序
砸二維線段樹(X
二維偏序
掃描線 :
照 \(x\) 排序,用BIT維護 \(y\) 前綴和
\(O(NlogN)\)
三維偏序
二維線段樹 + 掃描線?
三維偏序
對 \(z\) 分治,照 \(x\) 排序,用BIT維護 \(y\) 前綴和
\(O(Nlog^2N)\)
扣
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
struct ooo{
int x, y, z, t;
};
array<int, 100004> ans, BIT;
bool cmp(ooo a, ooo b){
if(a.z != b.z) return a.z > b.z;
return a.y < b.y;
}
void update(int p, int x){
for(; p < 100004; p += p & -p) BIT[p] += x;
}
int query(int p){
int sum = 0;
for(; p; p -= p & -p) sum += BIT[p];
return sum;
}
void CDQ(vector<ooo> &Q){
if(Q.size() <= 1) return;
int p = 0;
vector<ooo> L, R;
for(int i = 0; i < Q.size(); i++){
if(i < Q.size() / 2) L.pb(Q[i]);
else R.pb(Q[i]);
}
CDQ(L), CDQ(R);
Q.clear();
for(auto [rx, ry, rz, rt] : R){
while(p < L.size()){
auto [lx, ly, lz, lt] = L[p];
if(rx >= lx) break;
update(ly, 1);
Q.pb(L[p++]);
}
ans[rt] += query(100000) - query(ry);
Q.pb({rx, ry, rz, rt});
}
for(int i = 0; i < p; i++){
auto [lx, ly, lz, lt] = L[i];
update(ly, -1);
}
while(p < L.size()) Q.pb(L[p++]);
}
signed main(){
int n, x, y, z;
vector<ooo> Q;
cin >> n;
for(int i = 0; i < n; i++){
cin >> x >> y >> z;
Q.pb({x, y, z, i});
}
sort(Q.begin(), Q.end(), cmp);
CDQ(Q);
for(int i = 0; i < n; i++) cout << ans[i] << "\n";
return 0;
}
跟離線什麼關係?
逆序數對
\(x = \) 位置,\(v = \) 值
若 \((i, j)\) 為逆序數對 :
\(x_i < x_j \ or \ x_j < x_i\)
\(v_i > v_j \ or \ v_j > v_i\)
看起來就很二維偏序
把時間變成一個維度
題目是刪除元素,感覺很困難
因此可以倒著想,刪除就變成加入了,好像比較好 (?
變成三維偏序
\(t = \) 加入時間,\(x = \) 位置,\(v = \) 值
若 \((i, j)\) 為逆序數對 :
\(t_i \le t_j\)
\(x_i < x_j \ or \ x_j < x_i\)
\(v_i > v_j \ or \ v_j > v_i\)
扣
#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
struct ooo{
int t, x, v;
};
array<int, 100004> BIT, ans;
array<vector<int>, 100004> S;
map<int, int> M;
bool cmp(ooo a, ooo b){
if(a.t != b.t) return a.t < b.t;
return a.x < b.x;
}
void update(int p, int x){
for(; p < 100004; p += p & -p) BIT[p] += x;
}
int query(int p){
int sum = 0;
for(; p; p -= p & -p) sum += BIT[p];
return sum;
}
void CDQ(vector<ooo> &Q){
if(Q.size() <= 1) return;
int p = 0;
vector<ooo> L, R;
for(int i = 0; i < Q.size(); i++){
if(i < Q.size() / 2) L.pb(Q[i]);
else R.pb(Q[i]);
}
CDQ(L), CDQ(R);
Q.clear();
for(auto [rt, rx, rv] : R){
while(p < L.size()){
auto [lt, lx, lv] = L[p];
if(rx < lx) break;
update(lv, 1);
Q.pb(L[p++]);
}
ans[rt] += query(100000) - query(rv) - query(rv - 1);
Q.pb({rt, rx, rv});
}
while(p < L.size()){
auto [lt, lx, lv] = L[p];
update(lv, 1);
Q.pb(L[p++]);
}
for(auto [rt, rx, rv] : R) ans[rt] += query(rv - 1);
for(auto [lt, lx, lv] : L) update(lv, -1);
}
signed main(){
int n, m, d, v, cnt = 1;
vector<ooo> Q;
cin >> n >> m;
for(int i = 0; i < n; i++){
cin >> v;
Q.pb({0, i, v});
M[v] = 0;
}
for(auto &[x, c] : M) c = cnt++;
for(int i = 0; i < n; i++){
Q[i].v = M[Q[i].v];
S[Q[i].v].pb(i);
}
for(int i = m; i; i--){
cin >> d;
for(int s : S[M[d]]) Q[s].t = i;
}
sort(Q.begin(), Q.end(), cmp);
CDQ(Q);
for(int i = 1; i <= m; i++) ans[i] += ans[i - 1];
for(int i = m; i; i--) cout << ans[i] << "\n";
return 0;
}
提募
扣
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
struct ooo{
int p, l, r, v, t;
};
array<int, 100004> V, E, D, bar, las, ans;
array<set<int>, 100004> S;
void update(array<int, 100004> &BIT, int p, int x){
if(!p){
BIT[0] += x;
return;
}
for(; p < 100004; p += p & -p) BIT[p] += x;
}
int query(array<int, 100004> &BIT, int p){
int sum = BIT[0];
for(; p; p -= p & -p) sum += BIT[p];
return sum;
}
void add(vector<ooo> &Q, int s, int t, int p, int x){
if(s){
auto l = --S[s].find(p), r = ++S[s].find(p);
Q.pb({1, *l, p, -s, x});
if(r != S[s].end()){
Q.pb({1, p, *r, -s, x});
Q.pb({1, *l, *r, s, x});
}
S[s].erase(p);
}
if(t){
S[t].insert(p);
auto l = --S[t].find(p), r = ++S[t].find(p);
Q.pb({1, *l, p, t, x});
if(r != S[t].end()){
Q.pb({1, *l, *r, -t, x});
Q.pb({1, p, *r, t, x});
}
}
}
void CDQ(vector<ooo> &Q){
if(Q.size() <= 1) return;
int p = 0;
vector<ooo> L, R;
for(int i = 0; i < Q.size(); i++){
if(i < Q.size() / 2) L.pb(Q[i]);
else R.pb(Q[i]);
}
CDQ(L), CDQ(R);
Q.clear();
for(auto [rp, rl, rr, rv, rt] : R){
while(p < L.size()){
auto [lp, ll, lr, lv, lt] = L[p];
if(lr > rr) break;
if(lp == 1){
update(bar, ll, lv);
update(bar, lr, -lv);
}else if(lp == 2) update(las, ll, lv);
Q.pb(L[p++]);
}
Q.pb({rp, rl, rr, rv, rt});
if(rp == 3) ans[rt] += query(las, 100000) - query(las, rl - 1) + query(bar, rl - 1);
}
for(int i = 0; i < p; i++){
auto [lp, ll, lr, lv, lt] = L[i];
if(lp == 1){
update(bar, ll, -lv);
update(bar, lr, lv);
}else if(lp == 2) update(las, ll, -lv);
}
while(p < L.size()) Q.pb(L[p++]);
}
signed main(){
int n, q, t, l, r, p, v;
vector<ooo> Q;
cin >> n >> q;
for(int i = 1; i <= n; i++) S[i].insert(0);
for(int i = 1; i <= n; i++){
cin >> V[i];
l = *--S[V[i]].upper_bound(i);
add(Q, 0, V[i], i, 0);
}
for(int i = 1; i <= q; i++){
cin >> t;
if(t == 1){
cin >> p >> v;
add(Q, V[p], v, p, i);
V[p] = v;
}else if(t == 2){
cin >> l >> r >> v;
Q.pb({2, l, r, v, i});
E[l] = r, D[l] = v;
}else if(t == 3){
cin >> l;
Q.pb({2, l, E[l], -D[l], i});
}else{
cin >> l >> r;
Q.pb({3, l, r, 0, i});
}
}
CDQ(Q);
for(int i = 0; i <= q; i++){
if(ans[i]) cout << ans[i] << "\n";
}
return 0;
}
拔掉網路線
By thanksone
拔掉網路線
- 831