[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';
}
标签:NOIP2015,return,int,Ynoi2012,充满,mid,查询,ask,操作
From: https://www.cnblogs.com/ccxswl/p/18447380