[题解] CF85D Sum of Medians

为什么你们代码那么清奇俊秀啊

为什么暴力都过了啊

为什么我这么菜啊...


请忽略上面的话 ==

CF: https://codeforces.com/problemset/problem/85/D

Luogu: https://www.luogu.com.cn/problem/CF85D

你要维护一个集合,支持加入或删除一个数(保证任意时刻元素都没有重复,且待删除的数一定在集合里)

然后每次询问,你要回答排序后(从小到大)下标(从1开始)(\% 5=3)的所有数的和。

所有数为正整数且不超过(10^9)

下面大概是一个不要动脑子的做法(

首先建一棵权值线段树,然后每个节点维护几个东西

  • (cnt),即这个节点所代表的值域区间里有多少个数
  • (s[0..4])(s[i])表示这个节点内的所有数排序后下标(\% 5=i)的数的和

上面两个东西随便算算就好了(具体看代码...)

然后(10^9)炸了...那就动态开点呗...

非常无脑且好写的代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e5 + 10;

struct node {
  int lc, rc;
  ll s[5]; int cnt;
} t[N * 40];
int rt = 0, siz = 0;

void pushup(int x) {
  int lc = t[x].lc, rc = t[x].rc, ls = t[lc].cnt;
  // 讨论左右节点
  for (int i = 0; i < 5; i++) t[x].s[i] = t[lc].s[i];
  for (int i = 0; i < 5; i++) t[x].s[(i + ls) % 5] += t[rc].s[i]; // 维护s[0..4]
  t[x].cnt = t[lc].cnt + t[rc].cnt;
}

void insert(int &x, int l, int r, int p, int v) { // p插入的数的值,v=-1删除,v=1加入
  if (!x) x = ++siz; // 动态开点 
  if (l == r) {
    t[x].cnt += v;
    t[x].s[1] += 1ll * l * v;
    return;
  }
  int mid = (l + r) >> 1;
  if (p <= mid) insert(t[x].lc, l, mid, p, v);
  else insert(t[x].rc, mid + 1, r, p, v);
  pushup(x);
}

int main() {
  char s[23];
  int _; for (scanf("%d", &_); _; _--) {
    scanf("%s", s);
    if (s[0] == 's') printf("%lld
", t[rt].s[3]);
    else {
      int d = s[0] == 'd' ? -1 : 1, v;
      scanf("%d", &v);
      insert(rt, 1, 1e9, v, d);
    }
  }
  return 0;
}

原文地址:https://www.cnblogs.com/wxq1229/p/12817997.html