HDU 4288 Coder (线段树)

Coder

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4288

题意:有三种类型的操作,(1)."add x",表示往集合里加入?数x。(2).“del x”表示将集合中数x删除。(3).“sum”求出从小到大排列的集合中下标模5为3的数的和。集合中的数都是唯一的。

思路:这题巧妙的地方在于先离线输入,然后离散化。输入的数字依照从小到大排序,然后作为线段树的叶子结点。每一个结点包括两个部分,一是该结点包括的数字个数,二是依照区间内模5的余数分组求和。当须要向上pushup时,左子树的区间不变,而右子树的区间内,每一个数字的位置发生改变,一開始为i,之后变为i+cnt(cnt表示左子树区间内数字个数)

代码:

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<fstream>
#include<cstring>
#include<ctype.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, n) for (int i = 0; i < n; i++)
#define debug puts("===============")
typedef long long ll;
using namespace std;
const int maxn = 100200;
ll sum[maxn << 2][5];
int cnt[maxn << 2];
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
int n, tot, op[maxn], a[maxn];
char str[maxn][10];
void pushup(int rt) {
    cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1];
    int p = cnt[rt << 1];
    for (int i = 0; i < 5; i++) {
        sum[rt][i] = sum[rt << 1][i] + sum[rt << 1 | 1][((i - p) % 5 + 5) % 5];
    }
    //cout<<rt<<" "<<cnt[rt]<<endl;
}
void update(int pos, int x, int l, int r, int rt) {
    if (l == r) {
        if (x == 1) {
            sum[rt][1] = a[pos - 1];
            cnt[rt] = 1;
        } else {
            sum[rt][1] = 0;
            cnt[rt] = 0;
        }
        return ;
    }
    int m = (l + r) >> 1;
    if (pos <= m) update(pos, x, lson);
    else update(pos, x, rson);
    pushup(rt);
}
void build(int l, int r, int rt) {
    for (int i = 0; i < 5; i++) sum[rt][i] = 0;
    cnt[rt] = 0;
    if (l == r) return ;
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
}
int main () {
    while(~scanf("%d", &n)) {
        tot = 0;
        for (int i = 0; i < n; i++) {
            scanf("%s", str[i]);
            if (str[i][0] != 's') {
                scanf("%d", op + i);
                a[tot++] = op[i];
            }
        }
        sort(a, a + tot);
        tot = unique(a, a + tot) - a;
        build(1, tot, 1);
        for (int i = 0; i < n; i++) {
            if (str[i][0] == 's') printf("%I64d\n", sum[1][3]);
            else {
                int pos = lower_bound(a, a + tot, op[i]) - a + 1;
                if (str[i][0] == 'a') update(pos, 1, 1, tot, 1);
                else update(pos, -1, 1, tot, 1);
            }
        }
    }
    return 0;
}<strong>
</strong>
时间: 2024-10-16 09:59:39

HDU 4288 Coder (线段树)的相关文章

hdu 4288 Coder (线段树+离线)

题意: 刚开始有一个空集合.有三种操作: 1.往集合中加入一个集合中不存在的数 x 2.从集合中删除一个已经存在的数 x 3.计算集合的digest sum并输出.       digest sum求法:将集合中所有数从小到大排序,得到a1<a2<...<an. digest sum = sum(ai) where i mod 5 = 3 数据范围: N ( 1 <= N <= 105 ) 1 <= x <= 109. For any “add x” it is

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

hdu 4288 Coder

http://acm.hdu.edu.cn/showproblem.php?pid=4288 题意:add 就是在集合里面加上一个数x: del 就是从集合里删去一个数x: sum是求位置i%5==3的数的和. tree[i].sum[5] 里面数组存的是不同位置%5之后分别对应的和. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 100010 5 using

HDU 1828 Picture 线段树+扫描线

题意:给你一些矩形的左上角点的坐标和右下角点的坐标,求周长并 最显而易见的思路就是对于x轴和y轴做两次扫描线,对于负数的坐标进行离散化.每次增加的值是线段变化量的绝对值.具体写法和求面积并的差不多. #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt << 1 , l , m

HDU 1542 Atlantis(线段树扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6788    Accepted Submission(s): 2970 Problem Description There are several ancient Greek

POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的,这样理论上是对的 要注意处理高度相同的线段,把底边优先处理(在代码里就是f标记为1的线段),因为若是一个矩形的底边和另一个矩形的上边重合,则这个轮廓肯定不能算 不过POJ和HDU的数据好像都比较弱,我没进行上面的细节处理也AC了,不过一个很简单的数据就会不对,所以还是要处理一下才是真正正确的代码 我

hdu 1542 Atlantis(线段树&amp;扫描线&amp;面积并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6386    Accepted Submission(s): 2814 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

hdu 1828 Picture(线段树&amp;扫描线&amp;周长并)

Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2578    Accepted Submission(s): 1363 Problem Description A number of rectangular posters, photographs and other pictures of the same shap

hdu 1542 Atlantis(线段树)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6899    Accepted Submission(s): 3022 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

hdu 4864(2) 线段树

对task和machine的yi由小到大进行排序,然后对machine来跟task配对.当machine[].yi >= task[].yi时,就更新线段树,在1-1440上做线段树,线段树存的是task[].xi,同时用用优先队列保存task[].yi:当machine[].yi < task[].yi时,就查找 1到machine[].xi最大的值.如果存在最大值的话,把优先队列里的task[].yi取出来..这样一个machine就匹配到了一个最优的任务.还是看代码好好意会吧,细节挺多的