离散化
离散化就是一种映射,可以将大区间较分散的点,映射到小区间密集的点。或者说原数组中被赋值,被使用过的下标,映射到一个相对密集的下标区间。相对大小没有改变,却节省了储存空间。
如果数组数据范围<=1e5,可以用前缀和。
对a[x]+=c,用s[K]-s[L-1]来求前缀和。
如果数据范围很大,则需要用到离散化。
vector <整数> alls;的操作
unique(x,y)函数可以把一段数组的重复元素放到“后边”,并返回重复元素的起始下标。
find(x,y)函数可以去掉数组在x到y区间内的全部元素。
区间和
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
map<int,int>mp;//离散化
int a[111111];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
mp.clear(); //格式化,避免下一个测试数据出问题
int n,q;
scanf("%d%d",&n,&q);
int count=0;//用来标记有几个不同的数的(不包括0),因为题意是问把某个数变成0,所以0不考虑
for(int i=1;i<=n;i++)
{
int num;
scanf("%d",&num);
a[i]=num;
if(num&&mp[num]==0) //如果这个数第一次出现,说明输入了一个新的数,所以conut+1
{
count++;
}
mp[num]++;//用mp来储存该数出现的次数
}
while(q--)
{
int x;
scanf("%d",&x);
if(x==1)
{
int p,v;
scanf("%d%d",&p,&v); //把第p个数,变成v
int y=a[p]; //先把第p个数记下来(这个数是还没改动之前的) ,记下来是为了下面,删掉时,这个数对应出现的次数-1
if(v&&mp[v]==0) //如果新加的数,是之前没出现过的,就count+1,出现过的话,就没必要了
{
count++;
}
mp[v]++; //v这个数出现次数+1
a[p]=v; //更新p位置的数为v
mp[y]--; //这是把之前那个旧的数,删掉,
if(y&&mp[y]==0) //如果旧的那个数完全没了,说明有个种类的数完全没了,conut-1
{
count--;
}
}
else
{
printf("%d\n",count); //count就是要输出的答案,即有几个不同的数(非零)
}
}
}
return 0;
}