hdu 4288 线段树+离线+离散化

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

开始的时候,果断TLE,做的方法是,线段树上仅仅维护%5==3的坐标,比如1 2 3 4 5 6 7  如果删除第三个数,就将3,6的位置全+1,就是向右偏移以为,但是求和还是很慢,所以即使10秒,还是TLE。。。

正确做法:

1、节点内维护sum[0...4]分别代表区间内%5==i的和

2、结点维护点的个数,cnt

3、离散化处理,然后每次插入时,经过的结点cnt+1或-1,叶子节点Sum[0]就是节点值,父节点的sum这样维护了:很不错的方法

void pushup(int rt)
{
    for(int i=0;i<5;i++)
        nodes[rt].sum[i]=nodes[ls(rt)].sum[i]+nodes[rs(rt)].sum[ ((i-nodes[ls(rt)].cnt)%5+5)%5 ];
}

4、离散化+离线,可以使删除数比较方便,不用map

新学会的离散化方法:

for(int i=0;i<n;i++)
{
    scanf("%d",&a[i]);
    tmp[num++]=a[i];
}
sort(tmp,tmp+num);
num=unique(tmp,tmp+num)-tmp;
//然后可以这样查询位置
int pos=lower_bound(tmp,tmp+num,a[i])-tmp;

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
#define IN(s) freopen(s,"r",stdin)
#define CL(a,b) memset(a,b,sizeof(a))
#define ll long long
#define ls(rt) rt*2
#define rs(rt) rt*2+1
const int MAXN = 1e5+100;

struct Node{
    int l,r;
    ll sum[5];  //
    int cnt;    //区间内数的个数
}nodes[MAXN*4];

int a[MAXN],n,tmp[MAXN];
char op[MAXN][6];

void build(int rt,int l,int r)
{
    nodes[rt].l=l;
    nodes[rt].r=r;
    nodes[rt].cnt=0;
    CL(nodes[rt].sum,0);
    if(l==r)return;
    int mid=(l+r)/2;
    build(ls(rt),l,mid);
    build(rs(rt),mid+1,r);
}

void pushup(int rt)
{
    for(int i=0;i<5;i++)
        nodes[rt].sum[i]=nodes[ls(rt)].sum[i]+nodes[rs(rt)].sum[ ((i-nodes[ls(rt)].cnt)%5+5)%5 ];
}

void update(int  rt, int pos, int d, int flag)
{
    nodes[rt].cnt+=flag;
    if(nodes[rt].l == nodes[rt].r)
    {
        nodes[rt].sum[0]+=d;
        return;
    }
    if(pos<=nodes[ls(rt)].r)update(ls(rt),pos,d,flag);
    else update(rs(rt),pos,d,flag);
    pushup(rt);
}

int main()
{
    //IN("hdu4288.txt");
    int num;
    while(~scanf("%d",&n))
    {
        num=0;
        for(int i=0;i<n;i++)
        {
            scanf("%s",op[i]);
            if(op[i][0]!='s')
            {
                scanf("%d",&a[i]);
                tmp[num++]=a[i];
            }
        }
        sort(tmp,tmp+num);
        num=unique(tmp,tmp+num)-tmp;
        build(1,1,num);
        for(int i=0;i<n;i++)
        {
            int pos=lower_bound(tmp,tmp+num,a[i])-tmp;
            if(op[i][0] == 'a')update(1,pos,a[i],1);
            if(op[i][0] == 'd')update(1,pos,-a[i],-1);
            if(op[i][0] == 's')printf("%I64d\n",nodes[1].sum[2]);
        }
    }
    return 0;
}

时间: 2024-08-06 17:52:10

hdu 4288 线段树+离线+离散化的相关文章

hdu 4288 线段树 + 离散化

题意:求一个动态的非递减序列中,下标 mod 5 == 3的元素和,可以向序列中添加和删除某些元素,且序列的单调性不变.保证在任意时间 序列中不会存在两个相同元素.保证输入合法 思路:保证在任意时间 序列中不会存在两个相同元素,也就说明如果将所有的值都插入序列中,每个值对应的位置是唯一的.所以将操作的值先保存下来,离散化处理出每个值对应的位置.离散化后,我们得到一个新的数列 uni_num[] .通过题意的描述,我们可以发现一个性质,每当我们在 i 位置插入或者删除一个 uni_num[k] 时

玲珑oj 1117 线段树+离线+离散化,laz大法

1117 - RE:从零开始的异世界生活 Time Limit:1s Memory Limit:256MByte Submissions:438Solved:68 DESCRIPTION 486到了异世界,看到了一群可爱的妹子比如蕾姆啊,艾米莉亚啊,拉姆啊,白鲸啊,怠惰啊等等!有一天膜女告诉486说她的能力可能不能再用了,因为膜女在思考一个数据结构题,没心情管486了.486说我来帮你做,膜女说你很棒棒哦! 给一个集合,最开始为空(不是数学上的集合)五个操作: 1.插入x2.把小于x的数变成x3

hdu 4288 线段树

没看懂先mark 题意: 维护一个有序数列{An},有三种操作: 1.添加一个元素. 2.删除一个元素. 3.求数列中下标%5 = 3的值的和. 解题思路: 看的各种题解,今天终于弄懂了. 由于线段树中不支持添加.删除操作,所以题解写的是用离线做法. 我们来看它是如何解决添加.删除的问题的. 首先将所有出现过的数记录下来,然后排序去重,最后根据去重结果建树,然后每个操作数都会对应线段树中的一个点. 遇到添加.删除操作的时候,只要把那个节点的值改变,然后将它对下标的影响处理好就可以. 那么如何处理

HDU4288-Coder(线段树+离线+离散化)

Coder Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3183    Accepted Submission(s): 1254 Problem Description In mathematics and computer science, an algorithm describes a set of procedures

hdu 4288 线段树 暴力 **

题意: 维护一个有序数列{An},有三种操作: 1.添加一个元素. 2.删除一个元素. 3.求数列中下标%5 = 3的值的和. 解题思路: 看的各种题解,今天终于弄懂了. 由于线段树中不支持添加.删除操作,所以题解写的是用离线做法. 我们来看它是如何解决添加.删除的问题的. 首先将所有出现过的数记录下来,然后排序去重,最后根据去重结果建树,然后每个操作数都会对应线段树中的一个点. 遇到添加.删除操作的时候,只要把那个节点的值改变,然后将它对下标的影响处理好就可以. 那么如何处理这些操作对下标的影

HDU 3607 线段树+DP+离散化

题意:从左往右跳箱子,每个箱子有金币数量,只能从矮处向高处跳,求最大可获得金币数,数据规模1<=n<=1e5. 显然是一个dp的问题,不难得出dp[ i ] = max(dp[j] )+val [ i ] ,j < i ; 第一眼会想到o(n^2)的算法,显然会超时,这个时候就需要用线段树维护最大值,将复杂度降低到o(nlogn) 首先离散化处理,将高度从小到大排序,并使用unique函数去重,之后每个高度就可以映射为它的下标pos,然后用线段树维护每个下标对应的最优解bestans [

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

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

HDU 3642 线段树+离散化+扫描线

题意:给你N个长方体的左下角和右上角坐标,问你空间中有多少体积是被大于两个不同的立方体覆盖的.x,y~10^6 z~500 考虑到给的z比较小,所以可以直接枚举z,然后跑二维的扫描线就好. 关于处理被不同的线段覆盖三次的问题,可以维护四个信息,cnt,once,twice,more,然后相互推出结果就好. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #

gcd(线段树离线处理)——HDU 4630

对应HDU题目:点击打开链接 No Pain No Game Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1801    Accepted Submission(s): 770 Problem Description Life is a game,and you lose it,so you suicide. But you can