// 二分求出输入的坐标x的离散化下标 intfind(int x){// 找到第一个大于等于x的位置 int l = 0,r = alls.size()-1; while (l < r){ int mid = l+r>>1; if (alls[mid] < x) l = mid+1; else r = mid; } return r + 1;// 映射到1, 2, ...n,+1避免前缀和的下标问题 }
intmain(){ ios::sync_with_stdio(false);// 关闭同步流加速cin,cout cin >> n >> m; int x,c; for (int i = 0;i < n;i++){ cin >> x >> c; add.push_back({x,c}); alls.push_back(x); } int l,r; for (int i = 0;i < m;i++){ cin >> l >> r; query.push_back({l,r}); alls.push_back(l); alls.push_back(r); } // 排序,去重 sort(alls.begin(),alls.end()); alls.erase(unique(alls.begin(),alls.end()),alls.end()); // 处理插入 for (auto item : add){ int x = find(item.first); a[x] += item.second; } // 预处理前缀和 for (int i = 1;i <= alls.size();i++) s[i] = s[i-1] + a[i];// 注意取<= // 处理查询 for (auto item : query){ int l = find(item.first),r = find(item.second); cout << s[r] - s[l-1] << "\n"; } return0; }
拓展:手写unique函数。(双指针算法)
前提:已经从小到大排好序,目标:去重。
对于一个数列:1 2 2 3 3 4 5 5 7。
归纳出非重复元素的特点:
它是第一个元素;
$a[i] \ne a[i-1]$.
满足以上两点之一的元素就是非重复元素。
1 2 3 4 5 6 7 8
vector<int>::iterator unique(vector<int> &a){// 针对java、python等可以手动实现 // C++中比STL慢一点 int j = 0; for (int i = 0;i < a.size();i++){ if (!i || a[i] != a[i-1]) a[j++] = a[i];// j走得总比i慢 }// a[0] ~ a[j - 1] 存放所有a中不重复的数 return a.begin() + j; }
sort(segs.begin(),segs.end());// pair的sort排序,优先first排序,相同再second排序 int st = -2e9,ed = -2e9;// 初始化维护区间为-INF到-INF,本题可取-2e9 for (auto seg : segs){ if (ed < seg.first){ if (st != -2e9) res.push_back({st,ed});// 加入if判断避免n=1时存入[-2e9,-2e9] st = seg.first,ed = seg.second; } else{ ed = max(ed,seg.second); } }
if (st != -2e9) res.push_back({st,ed});// 加入if判断避免n=0时存入[-2e9,-2e9] segs = res; }
intmain(){ ios::sync_with_stdio(false); int n; cin >> n;
int l,r; while (n--){ cin >> l >> r; segs.push_back({l,r}); } merge(segs); cout << segs.size() << "\n";