值域大,个数小

两个问题

  1. 重复元素 > 去重
  2. 快速映射 > 二分

模板

  1. vector<int> alls; // 存储所有待离散化的值
  2. sort(alls.begin(), alls.end()); // 将所有值排序
  3. alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重复元素
  4. // 二分求出x对应的离散化的值
  5. int find(int x) // 找到第一个大于等于x的位置
  6. {
  7. int l = 0, r = alls.size() - 1;
  8. while (l < r)
  9. {
  10. int mid = l + r >> 1;
  11. if (alls[mid] >= x) r = mid;
  12. else l = mid + 1;
  13. }
  14. return r + 1; // 映射到1, 2, ...n
  15. }

运用

  1. //离散化,让大的数变成小的
  2. //用vector储存大的数,然后处理大的数a的时候,在vector中找到a,返回vector的下标x
  3. //在定义一个数组,a => x;处理a[x]即可
  4. #include <iostream>
  5. #include <cstring>
  6. #include <algorithm>
  7. #include <vector>
  8. using namespace std;
  9. typedef long long LL;
  10. typedef pair<int,int> PII;
  11. vector<int> alls;
  12. vector<PII> add,query;
  13. int a[300010],s[300010];
  14. int find(int x) // 找到x
  15. {
  16. int l= 0,r=alls.size()-1;
  17. while(l<r)
  18. {
  19. int mid = l+r >> 1;
  20. if(alls[mid]>=x) r=mid; //找x的最左边
  21. else l=mid+1;
  22. }
  23. return r+1; // 方便前缀和
  24. }
  25. int main()
  26. {
  27. int n,m;
  28. cin>>n>>m;
  29. for(int i=0;i<n;i++)
  30. {
  31. int x,c;
  32. cin>>x>>c;
  33. add.push_back({x,c});
  34. alls.push_back(x);
  35. }
  36. for(int i=0;i<m;i++)
  37. {
  38. int l,r;
  39. cin>>l>>r;
  40. query.push_back({l,r});
  41. alls.push_back(l);
  42. alls.push_back(r);
  43. }
  44. //排序
  45. sort(alls.begin(),alls.end());
  46. //去重
  47. alls.erase(unique(alls.begin(),alls.end()),alls.end());
  48. //处理插入
  49. for(auto item : add)
  50. {
  51. int x= find(item.first);
  52. a[x] += item.second;
  53. }
  54. //预处理前缀和
  55. for(int i=1;i<= alls.size();i++) s[i]=s[i-1]+a[i];
  56. //处理询问
  57. for(auto item : query)
  58. {
  59. int l = find(item.first);
  60. int r = find(item.second);
  61. cout<<s[r]-s[l-1]<<endl;
  62. }
  63. return 0;
  64. }

区间合并

image.png

  1. // 将所有存在交集的区间合并
  2. void merge(vector<PII> &segs)
  3. {
  4. vector<PII> res; //先定义一个新的PII
  5. sort(segs.begin(), segs.end()); //对于pair的排序,先按first,若相等,再按second;
  6. int st = -2e9, ed = -2e9;
  7. for (auto seg : segs) // 新的区间,分开的
  8. if (ed < seg.first)
  9. {
  10. if (st != -2e9) res.push_back({st, ed});
  11. st = seg.first, ed = seg.second;
  12. }
  13. else ed = max(ed, seg.second); //有相交的
  14. if (st != -2e9) res.push_back({st, ed}); //再把第13行的放进去
  15. segs = res; //更新
  16. }