[Ynoi2012] NOIP2015 充滿了希望
題意
給一個長為 \(n\) 的序列,有 \(m\) 個操作,操作編號從 \(1\) 到 \(m\),每個操作為:
1 x y
:將序列位置為 \(x,y\) 的兩個元素交換。
2 l r x
:將序列區間 \([l,r]\) 內所有元素修改為 \(x\)。
3 x
:查詢序列 \(x\) 位置的值。
現在有 \(q\) 次查詢,每次查詢給出一個操作的區間 \([l,r]\):
先將序列中的元素全部置為 \(0\),之後依次進行從 \(l\) 到 \(r\) 的所有操作,求出所有這些操作中所有 \(3\) 操作的答案的和。
查詢之間獨立。
思路
套路一樣
用線段樹維護一個元素被哪一次的操作染色(操作的編號)。對詢問離線,按 \(r\) 排序,對其做掃描線。
由於詢問已經拍好序,考慮第 \(i\) 個詢問的時候已經操作完了 \(1\sim r_i\) 的操作。我們只想要 \(l_i\sim r_i\) 之間操作貢獻的答案,如何消除 \(1\sim l_i-1\) 的操作對答案的影響呢?
把每次的操作三查詢出的答案以操作的時間為下標放到樹狀陣列裡,表示它會對之後的查詢造成影響,那我們詢問的時候就可以直接用樹狀陣列區間查詢統計答案。具體的,就是 bit.ask(r) - bit.ask(l-1)
。
大致思路就是這樣,具體的操作也比較好實現。操作一是兩個單點修改,操作二是區間覆蓋。
程式碼
#include <bits/stdc++.h>
using namespace std;
using ubt = long long;
inline int read() {
int s = 0, w = 1;
char c = getchar();
while (!isdigit(c)) {
if (c == '-')
w = -w;
c = getchar();
}
while (isdigit(c)) {
s = s * 10 + c - 48;
c = getchar();
}
return s * w;
}
const int maxN = 1e6 + 7;
int n, m, Q;
struct BIT {
ubt t[maxN];
void add(int x, int v) {
for (; x && x <= m; x += x & -x)
t[x] += v;
}
ubt ask(int x) {
ubt res = 0;
for (; x > 0; x -= x & -x)
res += t[x];
return res;
}
ubt query(int x, int y) {
return ask(y) - ask(x - 1);
}
} bit;
struct Tree {
int l, r;
int v, lz;
} t[maxN << 2];
#define ls (p << 1)
#define rs (p << 1 | 1)
void make(int p, int lz) {
t[p].lz = lz;
t[p].v = lz;
}
void down(int p) {
if (!t[p].lz) return;
make(ls, t[p].lz);
make(rs, t[p].lz);
t[p].lz = 0;
}
void build(int L, int R, int p) {
t[p].l = L, t[p].r = R;
if (L == R) return;
int mid = (L + R) >> 1;
build(L, mid, ls), build(mid + 1, R, rs);
}
void change(int L, int R, int p, int v) {
if (L <= t[p].l && t[p].r <= R)
make(p, v);
else {
down(p);
int mid = (t[p].l + t[p].r) >> 1;
if (L <= mid)
change(L, R, ls, v);
if (R > mid)
change(L, R, rs, v);
}
}
int ask(int K, int p) {
if (t[p].l == t[p].r)
return t[p].v;
down(p);
int mid = (t[p].l + t[p].r) >> 1;
return K <= mid ? ask(K, ls) : ask(K, rs);
}
void Swap(int x, int y) {
int resx = ask(x, 1);
int resy = ask(y, 1);
change(x, x, 1, resy);
change(y, y, 1, resx);
}
struct modi {
int op, x, y, k;
int id;
} mo[maxN];
void modify(modi G) {
if (G.op == 1)
Swap(G.x, G.y);
if (G.op == 2)
change(G.x, G.y, 1, G.id);
if (G.op == 3) {
int t = ask(G.x, 1);
bit.add(t, mo[t].k);
}
}
struct ques {
int l, r, id;
friend bool operator < (ques A, ques B) {
return A.r < B.r;
}
} q[maxN];
ubt ans[maxN];
int main() {
n = read(), m = read(), Q = read();
build(1, n, 1);
mo[0].k = 0;
for (int i = 1; i <= m; i++) {
mo[i].id = i;
mo[i].op = read();
mo[i].x = read();
if (mo[i].op != 3) {
mo[i].y = read();
if (mo[i].op == 2)
mo[i].k = read();
}
}
for (int i = 1; i <= Q; i++)
q[i].l = read(), q[i].r = read(), q[i].id = i;
sort(q + 1, q + Q + 1);
int now = 1;
for (int nw = 1; nw <= Q; nw++) {
int l = q[nw].l, r = q[nw].r;
while (now <= m && now <= r)
modify(mo[now++]);
ans[q[nw].id] = bit.query(l, r);
}
for (int i = 1; i <= Q; i++)
cout << ans[i] << '\n';
}