|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
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;
}
|
评分
-
查看全部评分
|