P3939 数颜色
题目背景
大样例下发链接:http://pan.baidu.com/s/1c0LbQ2 密码:jigg
题目描述
小 C 的兔子不是雪白的,而是五彩缤纷的。每只兔子都有一种颜色,不同的兔子可能有 相同的颜色。小 C 把她标号从 1 到 n" role="presentation" style="position: relative;">nn 的n" role="presentation" style="position: relative;">nn 只兔子排成长长的一排,来给他们喂胡萝卜吃。 排列完成后,第 ii 只兔子的颜色是4ai" role="presentation" style="position: relative;">4ai4ai 。俗话说得好,“萝卜青菜,各有所爱”。小 C 发现,不同颜色的兔子可能有对胡萝卜的 不同偏好。比如,银色的兔子最喜欢吃金色的胡萝卜,金色的兔子更喜欢吃胡萝卜叶子,而 绿色的兔子却喜欢吃酸一点的胡萝卜……为了满足兔子们的要求,小 C 十分苦恼。所以,为 了使得胡萝卜喂得更加准确,小 C 想知道在区间 [lj,rj]" role="presentation" style="position: relative;">[lj,rj][lj,rj]里有多少只颜色为 cj" role="presentation" style="position: relative;">cjcj 的兔子。
不过,因为小 C 的兔子们都十分地活跃,它们不是很愿意待在一个固定的位置;与此同 时,小 C 也在根据她知道的信息来给兔子们调整位置。所以,有时编号为 xj" role="presentation" style="position: relative;">xjxj和 xj+1" role="presentation" style="position: relative;">xj+1xj+1的两 只兔子会交换位置。 小 C 被这一系列麻烦事给难住了。你能帮帮她吗?
输入输出格式
输入格式:
从标准输入中读入数据。 输入第 1 行两个正整数 n" role="presentation" style="position: relative;">nn , m" role="presentation" style="position: relative;">mm 。
输入第 2 行 n" role="presentation" style="position: relative;">nn 个正整数,第 i" role="presentation" style="position: relative;">ii 个数表示第 i" role="presentation" style="position: relative;">ii 只兔子的颜色 ai" role="presentation" style="position: relative;">aiai。
输入接下来 mm 行,每行为以下两种中的一种:
“1 lj rj cj1" role="presentation" style="position: relative;">1 lj rj cj11 lj rj cj1 ” :询问在区间[lj,rj]" role="presentation" style="position: relative;">[lj,rj][lj,rj]里有多少只颜色为cj" role="presentation" style="position: relative;">cjcj 的兔子;
“ 2 xj" role="presentation" style="position: relative;">2 xj2 xj”: xj" role="presentation" style="position: relative;">xjxj和 xj+1" role="presentation" style="position: relative;">xj+1xj+1两只兔子交换了位置。
输出格式:
输出到标准输出中。
对于每个 1 操作,输出一行一个正整数,表示你对于这个询问的答案。
输入输出样例
输入样例#1:
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:
1
2
2
3
说明
【样例 1 说明】
前两个 1 操作和后两个 1 操作对应相同;在第三次的 2 操作后,3 号兔子和 4 号兔子
交换了位置,序列变为 1 2 2 3 3 3。
【数据范围与约定】
子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解 决一部分测试数据。 对于所有测试点,有 1≤lj<rj≤n" role="presentation" style="position: relative;">1≤lj<rj≤n1≤lj<rj≤n,1≤xj<n" role="presentation" style="position: relative;">1≤xj<n1≤xj<n 每个测试点的数据规模及特点如下表:
特殊性质 1:保证对于所有操作 1,有|rj−lj|≤20" role="presentation" style="position: relative;">|rj−lj|≤20|rj−lj|≤20或 |rj−lj|≤n−20" role="presentation" style="position: relative;">|rj−lj|≤n−20|rj−lj|≤n−20
特殊性质 2:保证不会有两只相同颜色的兔子。
好吧这又是一道水题,我可能是最近做数据结构做傻了,搞得连vector" role="presentation" style="position: relative;">vectorvector+二分这种技巧都搞忘了。没错,这道题标解就是vector" role="presentation" style="position: relative;">vectorvector+二分,但看到区间统计数的个数怎能不让人想到主席树呢?于是就有大佬对每种颜色建主席树跑过,但在我看来,这种方法和vector" role="presentation" style="position: relative;">vectorvector+二分的本质思想并没有区别,因此我另辟蹊径,自己yy" role="presentation" style="position: relative;">yyyy了一种做法(下来看了题解之后才发现自己又zz" role="presentation" style="position: relative;">zzzz了)。好吧我们对每个位置建一个主席树,然后主席树就成了前缀的形式,于是我们修改就与后面的前缀无关(因为从xj+1" role="presentation" style="position: relative;">xj+1xj+1到n" role="presentation" style="position: relative;">nn这些位置的每个数的权值仍然是不变的,这样的话操作2就变成了删除和插入操作的组合,不过貌似这样写会被卡常,本蒟蒻被卡了多次后乱改常数终于过了。事实证明switch" role="presentation" style="position: relative;">switchswitch的确快过if" role="presentation" style="position: relative;">ifif啊)
代码如下:
#include<bits/stdc++.h>
#define N 300005
using namespace std;
struct Node{int l,r,sum;}T[N*70];
int cnt=0,rt[N*70],n,m,col[N],siz=0;
inline void update(int &p,int last,int l,int r,int v,int tmp){
p=++cnt,T[p].l=T[last].l,T[p].r=T[last].r;
T[p].sum=T[last].sum+tmp;
if(l==r)return;
int mid=l+r>>1;
if(v<=mid)update(T[p].l,T[last].l,l,mid,v,tmp);
else update(T[p].r,T[last].r,mid+1,r,v,tmp);
}
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
return ans;
}
inline int query(int p,int l,int r,int v){
if(l==r)return T[p].sum;
int mid=l+r>>1;
if(v<=mid)return query(T[p].l,l,mid,v);
else return query(T[p].r,mid+1,r,v);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i)update(rt[i],rt[i-1],1,300000,col[i]=read(),1);
while(m--){
int op=read(),l=read();
switch(op){
case 1:{
int r=read(),c=read();
printf("%d\n",query(rt[r],1,300000,c)-query(rt[l-1],1,300000,c));
break;
}
default:{
update(rt[l],rt[l],1,300000,col[l],-1);
update(rt[l],rt[l],1,300000,col[l+1],1);
col[l]^=col[l+1],col[l+1]^=col[l],col[l]^=col[l+1];
break;
}
}
}
return 0;
}