CF-85D-Sum of Medians(线段树)

In one well-known algorithm of finding the k-th order statistics we should divide all elements into groups of five consecutive elements and find the median
of each five. A median is called the middle element of a sorted array (it‘s the third largest element for a group of five). To increase the algorithm‘s performance speed on a modern video card, you should be able to find a sum of medians in each five of the
array.

A sum of medians of a sorted k-element set S?=?{a1,?a2,?...,?ak},
where a1?<?a2?<?a3?<?...?<?ak,
will be understood by as

The  operator
stands for taking the remainder, that is  stands
for the remainder of dividing x by y.

To organize exercise testing quickly calculating the sum of medians for a changing set was needed.

Input

The first line contains number n (1?≤?n?≤?105),
the number of operations performed.

Then each of n lines contains the description of one of the three operations:

  • add x — add the element x to
    the set;
  • del x — delete the element x from
    the set;
  • sum — find the sum of medians of the set.

For any add x operation it is true
that the element x is not included in the set directly before the operation.

For any del x operation it is true
that the element x is included in the set directly before the operation.

All the numbers in the input are positive integers, not exceeding 109.

Output

For each operation sum print on the single line the sum of medians of the current
set. If the set is empty, print 0.

Please, do not use the %lld specificator to read or write 64-bit integers in C++. It is preferred to use the cin, cout streams
(also you may use the %I64d specificator).

Sample test(s)

input

6
add 4
add 5
add 1
add 2
add 3
sum

output

3

input

14
add 1
add 7
add 2
add 5
sum
add 6
add 8
add 9
add 3
add 4
add 10
sum
del 1
sum

output

5
11
13

思路:跟这题完全一样。点击打开链接  数据比HDU的强。

#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;

struct S{
char op[5];
int x,id;
}e[100005];

bool cmpval(S a,S b)
{
    if(a.x==b.x)  return a.op[0]<b.op[0];

    return a.x<b.x;
}

bool cmpid(S a,S b)
{
    return a.id<b.id;
}

int n,cnt,val[100005],num[400005];
long long sum[400005][5];

void build(int idx,int s,int e)
{
    if(s!=e)
    {
        int mid=(s+e)>>1;

        build(idx<<1,s,mid);
        build(idx<<1|1,mid+1,e);
    }

    num[idx]=0;

    for(int i=0;i<5;i++) sum[idx][i]=0;
}

void update(int idx,int s,int e,int pos,int flag)
{
    num[idx]+=flag;

    if(s==e)
    {
        sum[idx][1]+=val[s]*flag;

        return;
    }

    int mid=(s+e)>>1;

    if(pos<=mid) update(idx<<1,s,mid,pos,flag);
    else update(idx<<1|1,mid+1,e,pos,flag);

    for(int i=0;i<5;i++) sum[idx][i]=sum[idx<<1][i]+sum[idx<<1|1][i-num[idx<<1]%5>=0?i-num[idx<<1]%5:i-num[idx<<1]%5+5];//更新对应区间内下标为模5等于i数的和
}

long long query(int idx,int s,int e,int mod)
{
    return sum[idx<<1][mod]+sum[idx<<1|1][mod-num[idx<<1]%5>=0?mod-num[idx<<1]%5:mod-num[idx<<1]%5+5];
}

int main()
{
    int i;
    long long ans;

    while(~scanf("%d",&n))
    {
        map<int,int>mp;//用于离散化过程中判重,有可能存在先add a,再del a,再 add a的情况

        for(i=0;i<n;i++)
        {
            scanf("%s",e[i].op);

            if(e[i].op[0]=='s') e[i].x=0;
            else scanf("%d",&e[i].x);

            e[i].id=i;
        }

        sort(e,e+n,cmpval);

        cnt=1;

        for(i=0;i<n;i++)//离散化
        {
            if(e[i].op[0]=='a')
            {
                if(!mp[e[i].x]) mp[e[i].x]=cnt++;

                val[mp[e[i].x]]=e[i].x;
                e[i].x=mp[e[i].x];

            }
            else if(e[i].op[0]=='d')
            {
                e[i].x=mp[e[i].x];
            }
        }

        sort(e,e+n,cmpid);

        cnt--;

        if(!cnt)//特判
        {
            for(i=0;i<n;i++)
            {
                if(e[i].op[0]=='s')
                {
                    printf("0\n");
                }
            }

            continue;
        }

        build(1,1,cnt);

        for(i=0;i<n;i++)
        {
            if(e[i].op[0]=='a') update(1,1,cnt,e[i].x,1);
            else if(e[i].op[0]=='d') update(1,1,cnt,e[i].x,-1);
            else printf("%I64d\n",query(1,1,n,3));
        }
    }
}
时间: 2024-10-10 20:52:10

CF-85D-Sum of Medians(线段树)的相关文章

Codeforces 85D Sum of Medians(线段树)

85D Sum of Medians 题目链接 题意:一个集合有添加,删除元素,每次查询输出集合位置为i % 5 == 3的位置和 思路:线段树,线段树记录下% 5 == 0, 1, 2, 3, 4的和,并且记录一个mov表示右移多少,每次添加一个值的时候,就当前位置之后的一整段位置都要右移一个单位,这样去搞线段树维护一下即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <

codeforces 85D. Sum of Medians

二次联通门 : codeforces 85D. Sum of Medians /* codeforces 85D. Sum of Medians 正解线段树或是平衡树 结果用vector暴力卡过去了 */ #include <algorithm> #include <iostream> #include <cstdio> #include <vector> using namespace std; void read (int &now) { reg

codeforces CF920F SUM and REPLACE 线段树 线性筛约数

$ \Rightarrow $ 戳我进CF原题 F. SUM and REPLACE time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard input output: standard output Let $ D(x) $ be the number of positive divisors of a positive integer $ x $ . For example, $

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i)$以内肯定可以最终化为$1$或者$2$,所以线段树记录区间最大值和区间和,$Max\le2$就返回,单点暴力更新,最后线性筛预处理出$d$ 时间复杂度$O(m\log n)$ 代码 #include <bits/stdc++.h> using namespace std; typedef long

CF 46 D Parking Lot(线段树区间合并)

Description Nowadays it is becoming increasingly difficult to park a car in cities successfully. Let's imagine a segment of a street as long as L meters along which a parking lot is located. Drivers should park their cars strictly parallel to the pav

Educational Codeforces Round 72 (Rated for Div. 2)E. Sum Queries?(线段树区间合并)

https://codeforc.es/contest/1217/problem/E 建立9棵数位线段树维护区间最小值和次小值,建议用struct建树方便进行区间合并 1 #define bug(x) cout<<#x<<" is "<<x<<endl 2 #define IO std::ios::sync_with_stdio(0) 3 #include <bits/stdc++.h> 4 #define iter ::it

CF1217E Sum Queries? (线段树)

完了,前几天才说 edu 的 DEF 都不会,现在打脸了吧 qwq 其实在刚说完这句话 1min 就会了 D,3min 就会了 E 发现,对于大小 \(\ge 3\) 的不平衡集合,它至少有一个大小为 \(2\) 的子集是不平衡的. 证明,发现对于大小为 \(2\) 的集合,平衡当且仅当两数的数位交为空(对于任意一位,至多一个数在这一位上不是 \(0\)). 反证一波,如果大集合没有大小为 \(2\) 的不平衡集合,那么任意两数的数位交都为空,那么大集合也是平衡的,矛盾了. 所以,只需要考虑大小

[email&#160;protected] [307] Range Sum Query - Mutable / 线段树模板

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. The update(i, val) function modifies nums by updating the element at index i to val. Example: Given nums = [1, 3, 5] sumRange(0, 2) -> 9 update(1, 2

POJ 2886 Who Gets the Most Candies? 反素数+线段树

题意:变形的约瑟夫环模型,每个人有一个数字a,从第K个人开始出列,如果数字是正的,就往后数a个人出列,如果书负数,就往反方向数. 然后用最基本的线段树处理约瑟夫环的方法即可 但是题目要求的是第x个出列的人的名字,x为1-N中约数最多的数中的最小的那个.这里需要求反素数,即不大于N约数最多的. 写起来比较多,容易写错,一开始连素数打表都写作了QAQ #include <cstdio> #include <iostream> #include <cstring> #incl