|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
问题描述
给出有序的初始为空的集合, 维护操作
add x 把 x 插入
del x 把 x 删除
sum 求所有 下标 % 5 == 2 的数字的和
操作次数 n < 1e5, x < 1e9
错误原因
思路错误
没有想到权值线段树的权值有序性, 没有思考出左边区间的变化对右边区间下标的影响
反解下标出错了
解题思路
离线, 建立权值线段树, 每个节点存 % 5 的答案和区间长
因为每个数字是唯一的, add 就是 +, del 就是 -, 答案就是根节点的 s[3]
总结
在线题目先想离线怎么做, 一般会好些
看到想一直有序的序列, 或者数字重复次数不多, 值域大时想到权值线段树
- #include <bits/stdc++.h>
- using namespace std;
- typedef long long ll;
- const int N = 1e5 + 5;
- // 离线操作
- // 1add 2del 3sum
- struct Quest{
- int type, x;
- } Q[N];
- // 离散化
- int toid[N];
- int cnt;
- int id(int x){
- return (lower_bound(toid + 1, toid + cnt + 1, x) - toid);
- }
- int n;
- #define lc u<<1
- #define rc u<<1|1
- // 区间里数字个数, 每个下标 %5 的和
- struct Node{
- ll siz, s[5];
- } t[N << 2];
- void Up(Node & rt, Node & a, Node & b){
- for(int i = 0; i < 5; i++){
- rt.s[i] = a.s[i] + b.s[((i - a.siz) % 5 + 5) % 5];
- }
- rt.siz = a.siz + b.siz;
- }
- // +/- 一个数字在 p 位置
- void Modify(int u, int L, int R, int p, int v){
- if(L == p && R == p){
- t[u].s[1] += (ll)v*(ll)toid[L];
- t[u].siz += v;
- return ;
- }
- int mid = (L + R) >> 1;
- if(p <= mid) Modify(lc, L, mid, p, v);
- if(p > mid) Modify(rc, mid + 1, R, p, v);
- Up(t[u], t[lc], t[rc]);
- }
- int main(){
- ios::sync_with_stdio(0);
- cin.tie(0);
- cin >> n;
- for(int i = 1; i <= n; i++){
- string s;
- ll x;
- cin >> s;
- if(s[0] != 's'){
- cin >> x;
- toid[++cnt] = x;
- if(s[0] == 'a') Q[i].type = 1;
- else Q[i].type = 2;
- Q[i].x = x;
- continue;
- }
- Q[i].type = 3;
- }
- sort(toid + 1, toid + cnt + 1);
- int c = unique(toid + 1, toid + cnt + 1) - toid - 1;
- cnt = c;
- for(int i = 1; i <= n; i++){
- if(Q[i].type == 1){
- Modify(1, 1, cnt, id(Q[i].x), 1);
- }
- else if(Q[i].type == 2){
- Modify(1, 1, cnt, id(Q[i].x), -1);
- }
- else{
- cout << t[1].s[3] << '\n';
- }
- }
- return 0;
- }
复制代码
|
评分
-
查看全部评分
|