hdu4288 Coder(段树+分离)

主题链接:

huangjing

题意:

题目中给了三个操作

1:add x 就是把x插进去

2:delete x 就是把x删除

3:sum 就是求下标%5=3的元素的和。

另一个条件是插入和删除最后都要保证数列有序。

。。

首先告诉一种暴力的写法。

。由于时间很充足,须要对stl里面的函数有所了解。

就是直接申明一个vector的容器。然后直接用vector里面的操作比方 insert,erase等等操作。

。只是这个效率非常低。。

最后跑出来6000多ms。

。(强哥的代码)

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<cmath>
#include<string>
#include<queue>
#define eps 1e-9
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

char s[5];
int n;

vector<int>a;

int main()
{
    int len,val;
    vector<int>::iterator iter;
    while(cin>>n)
    {
        len=0;
        a.clear();
        while(n--)
        {
            scanf("%s",s);
            if(s[0]=='s')
            {
                long long ans = 0;
                for(int i=2; i < len ; i+=5)
                    ans += a[i];
                cout<<ans<<endl;
            }
            else if(s[0]=='a')
            {
                len++;
                scanf("%d",&val);
                iter=lower_bound(a.begin(),a.end(),val);
                a.insert(iter,val);
            }
            else
            {
                 len--;
                 scanf("%d",&val);
                 iter= lower_bound(a.begin(),a.end(),val);
                 a.erase(iter); // basic coding
            }
        }
    }
    return 0;
}

另外一种方法是线段树做法,这个要维护5颗线段树。结构体里面保存每一个节点的个数。首先由于线段树不支持插入,删除,要维护一个个数cnt,当插入一个数的时候,你看原来%3的数,如今取余肯定等于2,那么怎么办呢??那么这个cnt就起到了奇妙的作用。每当插入删除的时候就把对应的节点数变化,来维护那5棵线段树。

最后由于没有告诉数据范围,所以要採取离散化,然后离线处理,最后得出全部要操作的总个数,然后依此建树。第一次用离散化,认为好高大上。。。

代码:(參考自cxlove)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<cmath>
#include<string>
#include<queue>
#define eps 1e-9
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=100000+10;
int n,a[maxn],b[maxn];
char op[maxn][5];

struct Tree
{
    int cnt;
    ll sum[5];
}tree[maxn<<2];

void buildtree(int l,int r,int dex)
{
    tree[dex].cnt=0;
    memset(tree[dex].sum,0,sizeof(tree[dex].sum));
    if(l==r)  return;
    int mid=(l+r)>>1;
    buildtree(l,mid,dex<<1);
    buildtree(mid+1,r,dex<<1|1);
}

void push_up(int dex)
{
    for(int i=0;i<5;i++)
        tree[dex].sum[i]=tree[dex<<1].sum[i]+tree[dex<<1|1].sum[((i-tree[dex<<1].cnt)%5+5)%5];
}

void update(int l,int r,int dex,int pos,int flag,int val)
{
    tree[dex].cnt+=flag;
    if(l==r)
    {
        if(flag==1)
           tree[dex].sum[1]=val;
        else
           tree[dex].sum[1]=0;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)  update(l,mid,dex<<1,pos,flag,val);
    else update(mid+1,r,dex<<1|1,pos,flag,val);
    push_up(dex);
}

int main()
{
    int tot,pos,flag;
    while(~scanf("%d",&n))
    {
        tot=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",op[i]);
            if(op[i][0]!='s')
            {
                scanf("%d",&b[i]);
                a[tot++]=b[i];
            }
        }
        sort(a,a+tot);
        tot=unique(a,a+tot)-a;
        if(tot==0)  memset(tree[1].sum,0,sizeof(tree[1].sum));
        else buildtree(1,tot,1);
        for(int i=1;i<=n;i++)
        {
            pos=lower_bound(a,a+tot,b[i])-a;
            pos++;
            if(op[i][0]=='a')
            {
                flag=1;
                update(1,tot,1,pos,flag,b[i]);
            }
            else if(op[i][0]=='d')
            {
                flag=-1;
                update(1,tot,1,pos,flag,b[i]);
            }
            else
                printf("%I64d\n",tree[1].sum[3]);
        }
    }
    return 0;
}

版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-08-01 23:52:06

hdu4288 Coder(段树+分离)的相关文章

HDU4288 Coder(线段树)

注意添加到集合中的数是升序的,先将数据读入,再离散化. sum[rt][i]表示此节点的区域位置对5取模为i的数的和,删除一个数则右边的数循环左移一位,添加一个数则右边数循环右移一位,相当于循环左移4位,线段树与树状数组结合,树状数组确定位置. le[rt]表示左移的位数,区间更新懒惰标记 #include <iostream> #include <cstdio> #include<cstdlib> #include<map> #include<alg

Chang&#39;an(Black Box-线段树)

线段树 #include <bits/stdc++.h> using namespace std; struct rect{ int l, r, c, x; }; struct rec{ int x, p, ans, rank; }; rect tree[800004]; rec a[200004], get[20000]; bool cmpx(const rec &a, const rec &b){ return a.x<b.x; } bool cmpp(const r

HDU--2227--Find the nondecreasing subsequences--线段树

Find the nondecreasing subsequences Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1393    Accepted Submission(s): 494 Problem Description How many nondecreasing subsequences can you find in

hdu-4302-Holedox Eating-线段树-单点更新,有策略的单点查询

一開始实在是不知道怎么做,后来经过指导,猛然发现,仅仅须要记录某个区间内是否有值就可以. flag[i]:代表i区间内,共同拥有的蛋糕数量. 放置蛋糕的时候非常好操作,单点更新. ip:老鼠当前的位置 寻找吃哪一个蛋糕的时候: 1,要寻找0-ip这个区间内,位置最大的一个蛋糕的位置,记为ll. 2,要寻找ip-n这个区间内,位置最小的一个蛋糕的位置,记为rr. 找到ll,rr之后,就能够依据ll,rr跟ip的关系来确定该吃ll还是rr了. 怎样寻找ll呢? 假设在某个区间的右半边区间找到了一个数

hdu-4605-Magic Ball Game-线段树+离线操作

以前用树状数组做过一次,现在用线段树再刷一次... 首先必须先离散化... 然后建立2颗线段树,第一颗表示往左走,每个节点的值的分布. 第二颗表示往右走,每个节点的值的分布. 然后根据左右走的关系,判断出x,y的值. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<iostream> #include<stdlib.h> #inclu

段树 基于单点更新 敌人阵容

称号:敌人阵容 标准段树模板代码: #include<cstdio> #include<cstring> const int maxn = 500000 + 10; struct Node{ int left, right, count; }node[maxn]; int a[maxn]; /*********************************** ***************建树**************** ************i是区间序号********

HDU-5172-GTY&#39;s gay friends-线段树单点更新

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5172 题意:给出n个数,m个询问,问你[l,r]区间内是否为1到r-l+1的全排列. 大小很容易我们通过记录前缀和很容易求出来,但是关键是去重. 考虑线段树做法,我们记录每个点的靠左最近的相同元素的位置,然后求 整个区间的最大值(即最大的前驱)如果小于l,即满足条件,输出YES. 好吧,其实这个题目我是搜的RMQ算法出来的,因为我想练一下RMQ算法,所以我就看了一下别人的博客,自己也写了一下,结果死

NOJ--1434&amp;&amp;1566--线段树

开始集训了 =-= 估计也就1 2星期的热度吧 自己 好好提高就是了 ~ 今天 起晚了.... 来做的时候 前面3题很水 看到第4个 很明显 线段树 不会手写了.. ----碎碎念 线段树 题目类型 貌似 一般分成 单点更新 区间查询 区间更新 单点查询 区间更新 区间查询 线段树的种类又分成  -- 点树 && (忘记了)... 反正2者的区别就是叶结点的不同与建树的时候 对于右子树的不同写法 一个是[1,1] 一个是[1,2]对于叶结点 一个是create(root<<1|

poj-1151-Atlantis-线段树求面积并

很裸的线段树求面积并. 坐标需要离散化一下. #include<stdio.h> #include<iostream> #include<stdlib.h> #include<string.h> #include<algorithm> #include<vector> #include<math.h> #include<map> #pragma comment(linker, "/STACK:1024