颜色
题目背景:
分析:树状数组 + 线段树 + set or 带修莫队 or 分块
第一眼带修莫队,思索了一下觉得貌似复杂度真的非常不稳啊······选择另辟蹊径,然后发现了比较稳的树套树做法,首先我们对于每一个位置记录其pre[i],表示上一个出现颜色c[i]的位置是pre[i],那么显然,对于一段区间l ~ r的询问,答案就是所有pre小于l - 1的地方的权值和,这个可以考虑用主席树维护,好了,如果没有修改操作的话,我们就可以用主席树一个log搞过去了,现在考虑修改操作,为了让修改不是nlog,那么我们直接在外层套一个树状数组,这样可以是修改和询问全部变成log2n,然后考虑修改的具体操作,显然我们需要快速查找某一位置的上一个颜色x出现的位置和下一个颜色x的出现位置,我们直接对每一个颜色开一个set,然后每一次lower_bound查询位置即可。
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
const int MAXN = 100000 + 10;
int n, m, t, x, y, cnt;
int c[MAXN], w[MAXN], last[MAXN];
std::set<int> color[MAXN];
std::set<int> :: iterator it, pre, suc;
int root[MAXN];
struct node {
int left, right, sum;
} tree[MAXN * 300];
inline void read_in() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%d", &c[i]);
for (int i = 1; i <= n; ++i) scanf("%d", &w[i]);
}
inline void insert(int &cur, int l, int r, int pos, int w) {
if (cur == 0) cur = ++cnt;
tree[cur].sum += w;
if (l == r) return ;
int mid = l + r >> 1;
if (pos <= mid) insert(tree[cur].left, l, mid, pos, w);
else insert(tree[cur].right, mid + 1, r, pos, w);
}
inline int query(int cur, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return tree[cur].sum;
int mid = l + r >> 1;
int ret = 0;
if (ql <= mid) ret += query(tree[cur].left, l, mid, ql, qr);
if (qr > mid) ret += query(tree[cur].right, mid + 1, r, ql, qr);
return ret;
}
inline int lowbit(int i) {
return i & -i;
}
inline void insert(int i, int pos, int w) {
for (; i <= n; i += lowbit(i)) insert(root[i], 0, n, pos, w);
}
inline void query(int l, int r) {
int ans = 0;
for (int i = r; i > 0; i -= lowbit(i))
ans += query(root[i], 0, n, 0, l - 1);
for (int i = l - 1; i > 0; i -= lowbit(i))
ans -= query(root[i], 0, n, 0, l - 1);
printf("%d\n", ans);
}
inline void modify(int pos, int x) {
int u = c[pos];
if (u == x) return ;
it = pre = suc = color[u].lower_bound(pos), pre--, suc++;
insert(pos, *pre, -w[u]);
if (suc != color[u].end())
insert(*suc, pos, -w[u]), insert(*suc, *pre, w[u]);
color[u].erase(it), color[x].insert(pos), c[pos] = x;
it = pre = suc = color[x].lower_bound(pos), pre--, suc++;
insert(pos, *pre, w[x]);
if (suc != color[x].end())
insert(*suc, *pre, -w[x]), insert(*suc, pos, w[x]);
}
inline void solve_tree() {
for (int i = 1; i <= n; ++i) color[i].insert(0);
for (int i = 1; i <= n; ++i)
color[c[i]].insert(i), insert(i, last[c[i]], w[c[i]]), last[c[i]] = i;
}
inline void solve_query() {
while (m--) {
scanf("%d%d%d", &t, &x, &y);
if (t == 1) modify(x, y);
else query(x, y);
}
}
int main() {
freopen("color.in", "r", stdin);
freopen("color.out", "w", stdout);
read_in();
solve_tree();
solve_query();
return 0;
}