离散化
整数,有序数列的离散化
作用:将值域很大,个数很少的$n$个数映射到$[1,n]$
问题:
- 原数组$a$中可能有重复元素:去重
- 如何算出$a[i]$离散化后的值:二分(原数组有序)
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include<bits/stdc++.h> using namespace std;
const int N=1e5+5; int n,a[N];
int find(int x){ int l=1,r=n; while(l<r){ int mid=l+r>>1; if(a[mid]>=x)r=mid; else l=mid+1; } if(a[l]==x)return l; return -1; }
int main(){ cin >> n; for(int i=1;i<=n;i++){ cin >> a[i]; } sort(a+1,a+n+1); n=unique(a+1,a+n+1)-(a+1); return 0; }
|
例题:共$n$次修改,每次把位置$x$加上$c$,$m$次询问,每次求出区间$[l,r]$的和。其中$-10^9\le x,l,r\le 10^9,1\le n,m \le 10^5$
分析:观察到值域非常大,而数的个数较小,于是使用离散化。输入时记录所有用的的数,并进行离散化,记录所有的操作,离散化后用$find$函数在新数组中修改,又因为题目要求区间和,可以用前缀和,于是在离散化后的数组中进行前缀和,输出时求离散化完的前缀和。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #include<bits/stdc++.h> using namespace std;
typedef pair<int,int>PII; const int N=3e5+5;
int n,m; int a[N],s[N]; int alls[N]; int sz; PII add[N],query[N];
int find(int x){ int l=1,r=sz; while(l<r){ int mid=l+r>>1; if(alls[mid]>=x)r=mid; else l=mid+1; } return l; }
int main(){ cin >> n >> m; for(int i=1;i<=n;i++){ int x,c; cin >> x >> c; add[i]={x,c}; alls[i]=x; sz++; } for(int i=1;i<=m;i++){ int l,r; cin >> l >> r; query[i]={l,r}; alls[n+i*2-1]=l; alls[n+i*2]=r; sz+=2; } sort(alls+1,alls+n+m*2+1); sz=unique(alls+1,alls+n+m*2+1)-(alls+1); for(int i=1;i<=n;i++){ int x=find(add[i].first); a[x]+=add[i].second; } for(int i=1;i<=alls[sz];i++){ s[i]=s[i-1]+a[i]; cout << s[i] << ' '; } for(int i=1;i<=m;i++){ cout << s[find(query[i].second)]-s[find(query[i].first)-1] << endl; } return 0; }
|