一个ACMer萌新 Happier233~
题目简述:
一个长度为n的数组,一共有m次操作,有两种操作:
- 修改pos的值为x
- 查询[L,R]范围内,权值在[X,Y]范围内的连续线段(线段内的权值相同)个数
n,m<=2e5
内存512MB,时限3.5秒
题目思路:
每次查询[L,R]范围内的线段,其实维护每个线段的开头的值就行了,然后查询[L+1,R]之间又多少个线段的开头,再算上L这个点开头的线段,查询这些线段头有多少是在[X,Y]范围内的,就是答案了。
之前正好在学习CDQ分治,看了看概念什么的,所以第一感觉这就是个CDQ分治啊,可惜网络赛的时候我还没学会CDQ,写不出来,心塞。
然后转头去做动态修改主席树了,每次修改的时候维护pos,pos+1是否是开头,以及变更情况,这样把权值更新进主席树就行了,每次查询[L+1,R]区间内[X,Y]的个数和,再计算L这个位置的值是否在[X,Y]范围内,这样就可以得到答案了。
出题人非常良心的放过了主席树的做法,内存和时间正好可以跑完主席树。
然后我学习网上别人的做法,优化了一下自己的主席树板子,这个代码可以在3秒内跑完,但优化之后可读性–(反正是板子,为了性能将就了)
啊,时隔N个月,发现当初AC的主席树代码怎么T了,难道是计蒜客的评测姬变慢了???顺手更新一下当初已经补完的CDQ分治代码
代码(动态主席树):
// 巨菜的ACMer-Happier233
#include <bits/stdc++.h>
using namespace std;
//-----
typedef double db;
typedef long long ll;
typedef unsigned int ui;
typedef vector<int> vi;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define fi first
#define se second
#define pw(x) (1ll << (x))
#define tw(x, k) (((x) >> k) & 1)
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define rep(i, l, r) for(int i=(l);i<(r);++i)
#define per(i, l, r) for(int i=(r)-1;i>=(l);--i)
#define mst(t, v, n) memset(t, v, sizeof(decltype(*(t))) * (n))
#define sf(x) scanf("%d", &(x))
#ifndef ACM_LOCAL
#define endl '\n'
#endif
const int N = int(2e5 + 10);
// m: update count,MAXN>=m*log(n)^2
const int MAXN = int(4e7 + 10);
const int LN = 40;
struct PSegTree {
const int *a;
pii ran;
int n;
int c[MAXN];
int tot = 0;
int lson[MAXN], rson[MAXN];
// t: static root,s: dynamic root
int t[N], s[N];
int build(int l, int r) {
int k = ++tot;
c[k] = 0;
if (l == r) {
return k;
}
int mid = (l + r) >> 1;
lson[k] = build(l, mid);
rson[k] = build(mid + 1, r);
return k;
}
// SegTree Range and n points, num can be nullptr
int init(int l, int r, int _n, const int num[]) {
tot = 0;
a = num;
ran = {l, r};
n = _n;
int rt = build(l, r);
for (int i = 0; i <= n; i++) t[i] = s[i] = rt;
return rt;
}
// update the root in k
void update(int k[], int rt[], int cnt, int p, int v) {
// calc
for (int i = 0; i < cnt; i++)
c[k[i]] = c[rt[i]] + v;
int l, r;
tie(l, r) = ran;
while (l < r) {
int mid = (l + r) >> 1;
// 下面的逗号表达式顺序不能换
if (p <= mid) {
// go left
for (int i = 0; i < cnt; i++) {
rson[k[i]] = rson[rt[i]], rt[i] = lson[rt[i]], k[i] = lson[k[i]] = ++tot;
}
r = mid;
} else {
// go right
for (int i = 0; i < cnt; i++) {
lson[k[i]] = lson[rt[i]], rt[i] = rson[rt[i]], k[i] = rson[k[i]] = ++tot;
}
l = mid + 1;
}
// calc
for (int i = 0; i < cnt; i++)
c[k[i]] = c[rt[i]] + v;
}
}
// build static tree
inline void change(int pos, int p, int v) {
if (v == 0) t[pos] = t[pos - 1];
else { // use int as the int[]
int rt = t[pos - 1];
int k = t[pos] = ++tot;
update(&k, &rt, 1, p, v);
}
}
int use1[LN], use2[LN];
inline void add(int pos, int p, int v) {
// memory reuse
int *k = use1, *rt = use2;
int cnt = 0;
for (int i = pos; i <= n; i += (i & -i), cnt++) {
rt[cnt] = s[i], s[i] = k[cnt] = ++tot;
}
update(k, rt, cnt, p, v);
}
// calc lson value in use
inline int sum(int use[], int cnt) {
int ans = 0;
for (int i = 0; i < cnt; i++)
ans += c[lson[use[i]]];
return ans;
}
// calc value in use
inline int calc(int use[], int cnt) {
int ans = 0;
for (int i = 0; i < cnt; i++)
ans += c[use[i]];
return ans;
}
// ans=p1-p2
int query(int p1, int p2, int k) {
int r1 = t[p1], r2 = t[p2];
int cnt1 = 0, cnt2 = 0;
// calc root in need
for (int i = p1; i; i -= (i & -i)) use1[cnt1++] = s[i];
for (int i = p2; i; i -= (i & -i)) use2[cnt2++] = s[i];
int l, r;
tie(l, r) = ran;
int ans = 0;
while (l < r) {
int mid = (l + r) >> 1;
int cnt = c[lson[r1]] - c[lson[r2]] + sum(use1, cnt1) - sum(use2, cnt2);
if (k <= mid) {
// go left
r1 = lson[r1], r2 = lson[r2];
for (int i = 0; i < cnt1; i++) use1[i] = lson[use1[i]];
for (int i = 0; i < cnt2; i++) use2[i] = lson[use2[i]];
r = mid;
} else {
// go right
ans += cnt;
r1 = rson[r1], r2 = rson[r2];
for (int i = 0; i < cnt1; i++) use1[i] = rson[use1[i]];
for (int i = 0; i < cnt2; i++) use2[i] = rson[use2[i]];
l = mid + 1;
}
}
int cnt = c[r1] - c[r2] + calc(use1, cnt1) - calc(use2, cnt2);
ans += cnt;
return ans;
}
} tree;
int a[N], c[N];
void solve() {
int n, q;
while (cin >> n >> q) {
for (int i = 1; i <= n; i++) cin >> a[i];
c[1] = a[1];
for (int i = 2; i <= n; i++) c[i] = (a[i] == a[i - 1] ? 0 : a[i]);
tree.init(0, n, n, nullptr);
for (int i = 1; i <= n; i++) tree.change(i, c[i], c[i] > 0);
while (q--) {
int op;
cin >> op;
if (op == 1) {
int p, x;
cin >> p >> x;
if (a[p] == x) continue;
// del p
if (c[p]) {
tree.add(p, c[p], -1);
c[p] = 0;
}
// add p+1
if (p < n && a[p] == a[p + 1]) {
c[p + 1] = a[p + 1];
tree.add(p + 1, c[p], 1);
}
if (p < n && x == a[p + 1]) {
tree.add(p + 1, c[p + 1], -1);
c[p + 1] = 0;
}
a[p] = x;
// add p
if (p == 1 || a[p - 1] != a[p]) {
c[p] = a[p];
tree.add(p, c[p], 1);
}
} else {
int l, r, x, y;
cin >> l >> r >> x >> y;
int cnty = 0, cntx = 0;
cnty = tree.query(r, l, y);
cntx = tree.query(r, l, x - 1);
int ans = cnty - cntx + (a[l] >= x && a[l] <= y);
cout << ans << endl;
}
}
}
}
int main() {
#ifdef ACM_LOCAL
freopen("./data/std.in", "r", stdin);
// freopen("./data/std.out", "w", stdout);
#else
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#endif
#ifdef ACM_LOCAL
auto start = clock();
#endif
int t = 1;
// cin >> t;
while (t--)
solve();
#ifdef ACM_LOCAL
auto end = clock();
cerr << "Run Time: " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
#endif
return 0;
}
###代码(CDQ分治)
// 巨菜的ACMer-Happier233
#include <bits/stdc++.h>
using namespace std;
//-----
typedef double db;
typedef long long ll;
typedef unsigned int ui;
typedef vector<int> vi;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define fi first
#define se second
#define pw(x) (1ll << (x))
#define bt(x, k) (((x) >> k) & 1)
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define rep(i, l, r) for(int i=(l);i<(r);++i)
#define per(i, l, r) for(int i=(r)-1;i>=(l);--i)
#define mst(t, v, n) memset(t, v, sizeof(decltype(*(t))) * (n))
#define sf(x) scanf("%d", &(x))
#ifndef ACM_LOCAL
#define endl '\n'
#endif
const int N = int(3e5 + 10);
struct BITree {
int n;
ll c[N];
void init(int _n) {
n = _n + 1;
memset(c, 0, sizeof(ll) * n);
}
void change(int pos, ll v) {
for (int i = pos; i < n; i += i & (-i))
c[i] += v;
}
ll query(int x) {
ll ans = 0;
for (int i = x; i > 0; i -= i & (-i))
ans += c[i];
return ans;
}
void update(int l, int r, ll v) {
change(l, v);
change(r + 1, -v);
}
} tree;
struct node {
// time: 修改时间 | id: 0,1 | f: 正负 | x是下标 | y是权值
int time, id, f, x, y;
};
bool cmp(const node &a, const node &b) {
return a.x < b.x;
}
int ans[N];
node p[N << 2], et[N << 2];
void cdq(int l, int r) {
if (l + 1 == r) return;
int mid = (l + r) >> 1;
cdq(l, mid), cdq(mid, r);
int t = l;
for (int i = mid; i < r; i++) {
if (p[i].id)continue;
for (; t < mid && p[t].x <= p[i].x; t++) {
if (p[t].id) tree.change(p[t].y, p[t].f);;
}
int f = p[i].f;
int cnt = tree.query(p[i].y);
ans[p[i].time] += f * cnt;
}
// 逆操作p[t].y
while (--t >= l) {
if (p[t].id) tree.change(p[t].y, -p[t].f);
}
// 归并排序
int t1 = l, t2 = mid, k = 0;
while (t1 < mid && t2 < r) {
et[k++] = p[t1].x < p[t2].x ? p[t1++] : p[t2++];
}
copy(p + t1, p + mid, et + k);
copy(p + t2, p + r, et + k);
copy(et, et + (r - l), p + l);
}
int a[N];
int c[N];
void solve() {
int n, q;
while (cin >> n >> q) {
a[0] = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int tot = 0;
for (int i = 1; i <= n; i++) {
if (a[i] != a[i - 1]) {
p[tot++] = {0, 1, 1, i, a[i]};
}
}
mst(c, 0, n + 1);
for (int i = 1; i <= q; i++) {
int op;
cin >> op;
if (op == 1) {
int pos, v;
cin >> pos >> v;
ans[i] = -1;
if (a[pos] == v) continue;
// del p
if (a[pos] != a[pos - 1]) {
p[tot++] = {i, 1, -1, pos, a[pos]};
}
// add pos+1
if (pos < n && a[pos] == a[pos + 1]) {
p[tot++] = {i, 1, 1, pos + 1, a[pos + 1]};
}
if (pos < n && v == a[pos + 1]) {
p[tot++] = {i, 1, -1, pos + 1, a[pos + 1]};
}
a[pos] = v;
// add pos
if (pos == 1 || a[pos - 1] != a[pos]) {
p[tot++] = {i, 1, 1, pos, a[pos]};
}
ans[i] = -1;
} else {
ans[i] = 0;
int l, r, x, y;
cin >> l >> r >> x >> y;
if (a[l] >= x && a[l] <= y && a[l] == a[l - 1]) {
ans[i] = 1;
}
p[tot++] = {i, 0, 1, r, y};
p[tot++] = {i, 0, -1, r, x - 1};
p[tot++] = {i, 0, -1, l - 1, y};
p[tot++] = {i, 0, 1, l - 1, x - 1};
}
}
tree.init(n);
cdq(0, tot);
for (int i = 1; i <= q; i++) {
if (~ans[i]) cout << ans[i] << endl;
}
}
}
int main() {
#ifdef ACM_LOCAL
freopen("./data/std.in", "r", stdin);
// freopen("./data/std.out", "w", stdout);
#else
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#endif
#ifdef ACM_LOCAL
auto start = clock();
#endif
int t = 1;
// cin >> t;
while (t--)
solve();
#ifdef ACM_LOCAL
auto end = clock();
cerr << "Run Time: " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
#endif
return 0;
}