题目链接
线段树(+)二分思路
思路
比赛看到这题时感觉是一棵线段树(+)主席树,然后因为不会带修改主席树就放弃了,最后发现还卡了树套树。
由于本题数据保证序列中相同的数字不会超过200个,因此我们将每个读入的数和修改之后的数一起离散化一遍,然后用一个(vector)记录每个数出现的下标,然后用线段树维护区间异或值。查询时就先查询得到的这个异或值(num)是否在离散化中出现过,不出现那么一定不会有(a_i)等于(num),此时答案就是(R-L+1);否则我们就在(num)对应的(vector)中进行二分求出(L)与(R)间的数的个数即可。但是比赛的时候我最后查询时忘记找到它对应离散化后的值然后一直(RE),然后和队友一起找了半个多小时也没找到,不然就六题了,成功背了一大锅。
代码实现如下
#include <bits/stdc++.h>
using namespace std;
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mem0(a) memset(a, 0, sizeof(a));
#define mem1(a) memset(a, -1, sizeof(a));
#define bug printf("*******
");
#define debug(x) cout<<"["<<x<<"]"<<endl;
#define name2str(x) #x;
#define fuck(x) cout<<#x" = "<<x<<endl
typedef long long LL;
typedef pair<int, int> pii;
typedef pair<LL, int> pLi;
const int maxn = 1e6 + 7;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double pi = acos ( -1 );
int n, q;
int a[maxn];
vector<int> v, G[maxn + 100007];
vector<int>::iterator it;
struct pp {
int op, l, r;
} ask[100007];
struct node {
int l, r, num;
} segtree[maxn << 2];
void push_up ( int rt ) {
segtree[rt].num = ( segtree[lson].num ^ segtree[rson].num );
}
void build ( int rt, int l, int r ) {
segtree[rt].l = l, segtree[rt].r = r;
segtree[rt].num = 0;
if ( l == r ) {
segtree[rt].num = a[l];
return;
}
int mid = ( l + r ) >> 1;
build ( lson, l, mid );
build ( rson, mid + 1, r );
push_up ( rt );
}
void update ( int rt, int pos, int x ) {
if ( segtree[rt].l == segtree[rt].r ) {
segtree[rt].num = x;
return;
}
int mid = ( segtree[rt].l + segtree[rt].r ) >> 1;
if ( pos <= mid ) {
update ( lson, pos, x );
} else {
update ( rson, pos, x );
}
push_up ( rt );
}
int query ( int rt, int l, int r ) {
if ( segtree[rt].l == l && segtree[rt].r == r ) {
return segtree[rt].num;
}
int mid = ( segtree[rt].l + segtree[rt].r ) >> 1;
if ( r <= mid ) {
return query ( lson, l, r );
} else if ( l > mid ) {
return query ( rson, l, r );
} else {
return ( query ( lson, l, mid ) ^ query ( rson, mid + 1, r ) );
}
}
int main() {
scanf ( "%d%d", &n, &q );
for ( int i = 1; i <= n; ++i ) {
scanf ( "%d", &a[i] );
v.push_back ( a[i] );
}
build ( 1, 1, n );
for ( int i = 1; i <= q; ++i ) {
scanf ( "%d%d%d", &ask[i].op, &ask[i].l, &ask[i].r );
if ( ask[i].op == 1 ) {
v.push_back ( ask[i].r );
}
}
sort ( v.begin(), v.end() );
v.erase ( unique ( v.begin(), v.end() ), v.end() );
for ( int i = 1; i <= n; ++i ) {
a[i] = lower_bound ( v.begin(), v.end(), a[i] ) - v.begin() + 1;
G[a[i]].push_back ( i );
}
for ( int i = 1; i <= q; ++i ) {
if ( ask[i].op == 1 ) {
int pos = ask[i].l, val = ask[i].r;
update ( 1, pos, val );
int num = lower_bound ( v.begin(), v.end(), val ) - v.begin() + 1;
G[num].push_back ( pos );
sort ( G[num].begin(), G[num].end() );
it = lower_bound ( G[a[pos]].begin(), G[a[pos]].end(), pos );
if ( it == G[a[pos]].end() ) {
continue;
}
G[a[pos]].erase ( it );
a[pos] = num;
} else {
int l = ask[i].l, r = ask[i].r;
int num = query ( 1, l, r );
it = lower_bound ( v.begin(), v.end(), num );
if ( it == v.end() ) {
printf ( "%d
", ask[i].r - ask[i].l + 1 );
} else if ( ( *it ) != num ) {
printf ( "%d
", ask[i].r - ask[i].l + 1 );
} else {
int cnt = 0;
num = lower_bound(v.begin(), v.end(), num) - v.begin() + 1;
int pos1 = upper_bound ( G[num].begin(), G[num].end(), ask[i].r ) - G[num].begin();
int pos2 = lower_bound ( G[num].begin(), G[num].end(), ask[i].l ) - G[num].begin();
cnt = pos1 - pos2;
printf ( "%d
", ask[i].r - ask[i].l + 1 - cnt );
}
}
}
return 0;
}
树套树写法
思路
假如数据并没有保证序列中相同的数字不会超过200个,那么用上述解法就无法解决,这个时候我们就可以使用树套树来解决。
我的解法是用一棵线段树维护区间异或值和上述解法一致,然后用树状数组(+)主席树来维护每个数对应的个数。
代码实现如下
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> piL;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********
")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("in","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)
const double eps = 1e-8;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
int n, q, tot1, tot2, cnt, tt;
int a[maxn*10], root1[maxn*10], root2[maxn*10];
int q1[maxn*10], q2[maxn*10], num[maxn*20];
struct pp {
int op, x, y;
}ask[maxn];
struct node {
int l, r, num;
}segtree[maxn*40], tree[maxn*500];
void push_up(int rt) {
segtree[rt].num = (segtree[lson].num ^ segtree[rson].num);
}
void build(int rt, int l, int r) {
segtree[rt].l = l, segtree[rt].r = r;
segtree[rt].num = 0;
if(l == r) {
segtree[rt].num = a[l];
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid); build(rson, mid + 1, r);
push_up(rt);
}
void update(int rt, int x, int val) {
if(segtree[rt].l == segtree[rt].r) {
segtree[rt].num = val;
return;
}
int mid = (segtree[rt].l + segtree[rt].r) >> 1;
if(x <= mid) update(lson, x, val);
else update(rson, x, val);
push_up(rt);
}
int query(int rt, int l, int r) {
if(segtree[rt].l == l && segtree[rt].r == r) {
return segtree[rt].num;
}
int mid = (segtree[rt].l + segtree[rt].r) >> 1;
if(r <= mid) return query(lson, l, r);
else if(l > mid) return query(rson, l, r);
else return (query(lson, l, mid) ^ query(rson, mid + 1, r));
}
int getid(int x) {
return lower_bound(num, num + tt, x) - num + 1;
}
void update1(int l, int r, int& x, int y, int pos, int val) {
tree[++cnt] = tree[y], tree[cnt].num += val, x = cnt;
if(l == r) return;
int mid = (l + r) >> 1;
if(pos <= mid) update1(l, mid, tree[x].l, tree[y].l, pos, val);
else update1(mid + 1, r, tree[x].r, tree[y].r, pos, val);
}
int query1(int l, int r, int x, int y, int pos) {
if(l == r) {
int ans = tree[y].num - tree[x].num;
for(int i = 0; i < tot1; ++i) ans -= tree[q1[i]].num;
for(int i = 0; i < tot2; ++i) ans += tree[q2[i]].num;
return ans;
}
int mid = (l + r) >> 1;
if(pos <= mid) {
for(int i = 0; i < tot1; ++i) q1[i] = tree[q1[i]].l;
for(int i = 0; i < tot2; ++i) q2[i] = tree[q2[i]].l;
return query1(l, mid, tree[x].l, tree[y].l, pos);
}else {
for(int i = 0; i < tot1; ++i) q1[i] = tree[q1[i]].r;
for(int i = 0; i < tot2; ++i) q2[i] = tree[q2[i]].r;
return query1(mid + 1, r, tree[x].r, tree[y].r, pos);
}
}
int main() {
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
num[tt++] = a[i];
}
for(int i = 1; i <= q; ++i) {
scanf("%d%d%d", &ask[i].op, &ask[i].x, &ask[i].y);
if(ask[i].op == 1) num[tt++] = ask[i].y;
}
sort(num, num + tt);
tt = unique(num, num + tt) - num;
int sz = tt;
build(1, 1, n);
for(int i = 1; i <= n; ++i) {
a[i] = getid(a[i]);
update1(1, sz, root1[i], root1[i-1], a[i], 1);
}
for(int i = 1; i <= q; ++i) {
if(ask[i].op == 1) {
int pos = ask[i].x, val = ask[i].y, x = a[pos];
a[pos] = val;
update(1, pos, val);
val = getid(val);
while(pos <= n) {
update1(1, sz, root2[pos], root2[pos], x, -1);
update1(1, sz, root2[pos], root2[pos], val, 1);
pos += lowbit(pos);
}
} else {
int numm = query(1, ask[i].x, ask[i].y);
int pos = lower_bound(num, num + tt, numm) - num;
if(pos == tt || num[pos] != numm) {
printf("%d
", ask[i].y - ask[i].x + 1);
continue;
}
numm = getid(numm);
tot1 = tot2 = 0;
pos = ask[i].x - 1;
while(pos) {
q1[tot1++] = root2[pos];
pos -= lowbit(pos);
}
pos = ask[i].y;
while(pos) {
q2[tot2++] = root2[pos];
pos -= lowbit(pos);
}
printf("%d
", ask[i].y - ask[i].x + 1 - query1(1, sz, root1[ask[i].x-1], root1[ask[i].y], numm));
}
}
return 0;
}
CDQ分治写法
代码实现如下
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********
")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)
const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 2e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
int n, m, tot;
vector<int> v;
int a[maxn*5], tree[maxn*5], num[maxn*6], ans[maxn*6];
struct que {
int num, op, pos, type, id;
bool operator < (const que& x) const {
return pos == x.pos ? op < x.op : pos < x.pos;
}
}ask[maxn*10], tmp[maxn*10];
void bit_update(int x, int val) {
for(; x <= n; x += lowbit(x)) {
tree[x] ^= val;
}
}
int bit_query(int x) {
int ans = 0;
while(x > 0) {
ans ^= tree[x];
x -= lowbit(x);
}
return ans;
}
struct node {
int l, r, op, num;
}q[maxn];
int getid(int x) {
return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}
void CDQ(int L, int R) {
if (L == R) return;
int mid = (L + R) >> 1;
CDQ(L, mid); CDQ(mid + 1, R);
int p = L, q = mid + 1;
for (int i = L; i <= R; i++) {
if ((p <= mid && ask[p] < ask[q]) || q > R) {
if (ask[p].op == 1) {
int x = ask[p].num;
num[x] += ask[p].type;
}
tmp[i] = ask[p++];
} else {
if (ask[q].op == 2) {
int x = ask[q].num;
ans[ask[q].id] += ask[q].type * num[x];
}
tmp[i] = ask[q++];
}
}
for (int i = L; i <= R; i++) {
if (i <= mid) {
if (ask[i].op == 1) {
int x = ask[i].num;
num[x] -= ask[i].type;
}
}
ask[i] = tmp[i];
}
}
int main(){
#ifndef ONLINE_JUDGE
FIN;
freopen("out.txt","w",stdout);
#endif
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
v.push_back(a[i]);
bit_update(i, a[i]);
}
for(int i = 1; i <= m; ++i) {
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
q[i].op = op, q[i].l = x, q[i].r = y;
if(op == 1) {
v.push_back(y);
int num = (bit_query(x-1) ^ bit_query(x));
bit_update(x, num);
bit_update(x, y);
} else {
q[i].num = (bit_query(x - 1) ^ bit_query(y));
v.push_back(q[i].num);
}
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
int cnt = 0;
for(int i = 1; i <= n; ++i) {
ask[++tot] = {getid(a[i]), 1, i, 1, 0};
}
for(int i = 1; i <= m; ++i) {
int op = q[i].op, x = q[i].l, y = q[i].r, num = q[i].num;
if(op == 1) {
ask[++tot] = {getid(a[x]), 1, x, -1, 0};
ask[++tot] = {getid(y), 1, x, 1, 0};
a[x] = y;
} else {
ask[++tot] = {getid(num), 2, x - 1, 1, ++cnt};
ask[++tot] = {getid(num), 2, y, -1, cnt};
ans[cnt] = y - x + 1;
}
}
CDQ(1, tot);
for(int i = 1; i <= cnt; ++i) {
printf("%d
", ans[i]);
}
return 0;
}
带修改莫队写法
代码实现如下
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> piL;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********
")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("in","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)
const double eps = 1e-8;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
int n, q, block, all;
int a[maxn];
unordered_map<int,int> cnt;
struct que {
int l, r, id, t, ans;
bool operator < (const que& x) const {
if((l - 1) / block != (x.l - 1) / block) {
return l < x.l;
}
if((r - 1) / block != (x.r - 1) / block) {
return r < x.r;
}
return t < x.t;
}
}ask[maxn];
struct modify {
int pre, val, pos;
}mfy[maxn];
void del(int x) {
cnt[x]--;
all ^= x;
}
void add(int x) {
cnt[x]++;
all ^= x;
}
int main() {
#ifndef ONLINE_JUDGE
FIN;
freopen("out","w",stdout);
#endif
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
block = (int)pow(n, 2.0/3);
int nw = 0, idq = 0, idc = 1;
for (int i = 1; i <= q; i++) {
int op; scanf("%d", &op);
if (op == 2) {
scanf("%d%d", &ask[idq].l, &ask[idq].r);
ask[idq].id = idq;
ask[idq].t = nw;
idq++;
} else {
scanf("%d%d", &mfy[idc].pos, &mfy[idc].val); nw++;
mfy[idc].pre = a[mfy[idc].pos];
a[mfy[idc].pos] = mfy[idc].val;
idc++;
}
}
sort(ask, ask + idq);
int tmp = nw, r = 0, l = 1;
for (int i = 0; i < idq; i++) {
while (r < ask[i].r) add(a[++r]);
while (l > ask[i].l) add(a[--l]);
while (r > ask[i].r) del(a[r--]);
while (l < ask[i].l) del(a[l++]);
while (tmp < ask[i].t) {
tmp++;
if (mfy[tmp].pos >= ask[i].l && mfy[tmp].pos <= ask[i].r) {
del(mfy[tmp].pre);
add(mfy[tmp].val);
}
a[mfy[tmp].pos] = mfy[tmp].val;
}
while (tmp > ask[i].t) {
if (mfy[tmp].pos >= ask[i].l && mfy[tmp].pos <= ask[i].r) {
del(mfy[tmp].val);
add(mfy[tmp].pre);
}
a[mfy[tmp].pos] = mfy[tmp].pre;
tmp--;
}
int res = cnt[all];
ask[ask[i].id].ans = (r - l + 1) - res;
}
for(int i = 0; i < idq; ++i) {
printf("%d
", ask[i].ans);
}
return 0;
}