题目链接:
题意:
给定n只兔子和其颜色,接下来给m次行为,行为有两种,op=1时给定l,r,c,查询[l,r]区间内颜色为c的兔子有多少只,op=2时给定x,表示将位置x和x+1位置的两只兔子进行交换。(n<=3e5,1<=l,r,c,x<=n)
样例
输入
6 5 1 2 3 2 3 3 1 1 3 2 1 4 6 3 2 3 1 1 3 2 1 4 6 3
输出
1 2 2 3
思路:
一看是查询[l,r]区间满足某种条件的数量问题,直接就把主席树掏出来了,结果这题卡常卡的死死的,不过也没算白写,最起码让我知道了对主席树进行修改是依旧是通过insert的方式从旧版本更新而来,通过代码中注释掉的那部分来更新是不行的。
根据题目给定的数据的范围,我们可以将第c种颜色的兔子出现的位置存在一个vector vc[c]中,对于查询[l,r]中有多少只颜色为c的兔子,我们就通过lower_bound查询vc[c]中第一个大于等于l的位置,用upper_bound查询vc[c]中以一个大于r的位置,两者相减即[l,r]中c颜色兔子的数量。
对于将x和x+1处的兔子交换,那就更简单了,假设x和x+1处的兔子的颜色分别为c1和c2,那就从vc[c1]中找到x所在的位置,将该位置的数从x换成x+1就行了,同样从vc[c2]中找到x+1所在的位置,将该位置的数从x+1换成x就行了,这里最开始用迭代器进行更改时还出错了,错误代码我下面也给了,原因是x和x+1位置的兔子可能是一种颜色,进行下面的错误修改后对应改颜色的vc中x,x+1变成了x+1,x,不再满足递增,在后面查询的时候不满足二分的单调性了。
这样是错的
auto iter1=lower_bound(vc[a[x]].begin(),vc[a[x]].end(),x);
auto iter2=lower_bound(vc[a[x+1]].begin(),vc[a[x+1]].end(),x+1);
*iter1=x+1;
*iter2=x;
这样就是对的
auto iter1=lower_bound(vc[a[x]].begin(),vc[a[x]].end(),x);
*iter1=x+1;
auto iter2=lower_bound(vc[a[x+1]].begin(),vc[a[x+1]].end(),x+1);
*iter2=x;
以后建议以后用迭代器就是迭代器查完接着用,不要攒着一块用
代码:
TLE的主席树代码
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+10;
const int M=N*100;
int n,m;
int lch[M],rch[M],sum[M];
int root[N],tot=0;
int a[N];
void cpy(int from,int to){
lch[to]=lch[from];
rch[to]=rch[from];
sum[to]=sum[from];
}
void insert(int &u,int old,int L,int R,int x,int k){
u=++tot;
cpy(old,u);
sum[u]+=k;
if(L==R)
return;
int mid=(L+R)>>1;
if(x<=mid)
insert(lch[u],lch[u],L,mid,x,k);
else
insert(rch[u],rch[u],mid+1,R,x,k);
}
//void modify(int u,int L,int R,int x,int k){
// sum[u]+=k;
// if(L==R)
// return;
// int mid=(L+R)>>1;
// if(x<=mid)
// modify(lch[u],L,mid,x,k);
// else
// modify(rch[u],mid+1,R,x,k);
//}
int query(int s,int t,int L,int R,int x){
if(L==R)
return sum[t]-sum[s];
int mid=(L+R)>>1;
if(x<=mid)
return query(lch[s],lch[t],L,mid,x);
else
return query(rch[s],rch[t],mid+1,R,x);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
insert(root[i],root[i-1],1,N,a[i],1);
}
int op,l,r,c,x;
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&l,&r,&c);
printf("%d\n",query(root[l-1],root[r],1,N,c));
}
else{
scanf("%d",&x);
// modify(root[x],1,N,a[x],-1);
// modify(root[x],1,N,a[x+1],1);
insert(root[x],root[x-1],1,N,a[x+1],1);
insert(root[x+1],root[x],1,N,a[x],1);
swap(a[x],a[x+1]);
}
}
}
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+10;
vector<int> vc[N];
int a[N];
int n,m;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
vc[a[i]].push_back(i);
}
int op,l,r,c,x;
int pos1,pos2;
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&l,&r,&c);
pos1=lower_bound(vc[c].begin(),vc[c].end(),l)-vc[c].begin();
pos2=upper_bound(vc[c].begin(),vc[c].end(),r)-vc[c].begin();
printf("%d\n",pos2-pos1);
}
else{
scanf("%d",&x);
int c1=a[x],c2=a[x+1];
pos1=lower_bound(vc[c1].begin(),vc[c1].end(),x)-vc[c1].begin();
vc[c1][pos1]=x+1;
pos2=lower_bound(vc[c2].begin(),vc[c2].end(),x+1)-vc[c2].begin();
vc[c2][pos2]=x;
swap(a[x],a[x+1]);
}
}
}