[洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?

其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客

Description

现在请求你维护一个数列,要求提供以下两种操作:

1、 查询操作。

语法:Q L

功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。

限制:L不超过当前数列的长度。(L>=0)

2、 插入操作。

语法:A n

功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。

限制:n是整数(可能为负数)并且在长整范围内。

注意:初始时数列是空的,没有一个数。

Input&Output

Input

第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足(0<D<2,000,000,000)

接下来的M行,每行一个字符串,描述一个具体的操作。语法如上文所述。

Output

对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。

Sample

Input

5 100
A 96
Q 1
A 97
Q 1
Q 2

Output

96
93
96

Solution

  • 本来一开始打的线段树,但洛谷的加强数据T了最后一个点,所以改用了树状数组。因为只在队列末尾插入数据,所以其实线段树有点大材小用了。树状数组可以维护区间最大值,查询时通过不断更新ret即可。
  • 90分线段树(也可能是本蒟蒻太水了):
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define maxm 200001
    using namespace std;
    typedef long long ll;
    struct node{
    ll mx;
    int l,r,lc,rc;
    node(){
        lc=rc=-1;
    }
    }tree[maxm<<1];
    ll m,d,L,n,sum,t;
    char c;
    inline ll rd()
    {
    ll x=0;bool f=0;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return f?-x:x;
    }
    int cnt;
    int rt=cnt++;
    void pushup(int cur)
    {
    int lc=tree[cur].lc,rc=tree[cur].rc;
    tree[cur].mx=max(tree[lc].mx,tree[rc].mx);
    tree[cur].l=tree[lc].l;
    tree[cur].r=tree[rc].r;
    }
    void build(int l,int r,int cur)
    {
    if(l==r){
        tree[cur].mx=0;
        tree[cur].l=tree[cur].r=l;
        return;
    }
    int mid=(l+r)>>1;
    tree[cur].lc=cnt++;
    tree[cur].rc=cnt++;
    build(l,mid,tree[cur].lc);
    build(mid+1,r,tree[cur].rc);
    pushup(cur);
    }
    void upd(int pos,ll c,int cur)
    {
    if(tree[cur].l==tree[cur].r)
    {
        tree[cur].mx=c;
        return;
    }
    int mid=(tree[cur].l+tree[cur].r)>>1;
    if(pos<=mid)upd(pos,c,tree[cur].lc);
    if(pos>mid)upd(pos,c,tree[cur].rc);
    pushup(cur);
    }
    ll query(int l,int r,int cur)
    {
    if(tree[cur].l>=l&&tree[cur].r<=r){
        return tree[cur].mx;
    }
    int mid=(tree[cur].l+tree[cur].r)>>1;
    ll mx=0;
    if(l<=mid)mx=max(mx,query(l,r,tree[cur].lc));
    if(r>mid)mx=max(mx,query(l,r,tree[cur].rc));
    return mx;
    }
    int main()
    {
    m=rd();
    d=rd();
    build(1,200000,rt);
    for(int i=1;i<=m;++i)
    {
        cin>>c;
        if(c=='Q'){
            L=rd();
            t=query(sum-L+1,sum,rt);
            printf("%d\n",t);
        }
        else if(c=='A'){
            n=rd();
            ll tmp=(n%d+t%d)%d;
            upd(sum+1,tmp,rt);
            sum++;
        }
    }
    return 0;
    }
  • 树状数组:
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define maxn 200005
    using namespace std;
    typedef long long ll;
    ll mx(ll a,ll b)
    {
    return (a>b)?a:b;
    }
    inline ll rd()
    {
    ll x=0;char c=getchar();
    bool f=false;
    while(c<'0'||c>'9'){
        if(c=='-')f=true;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return f?-x:x;
    }
    ll b[maxn],d;
    int sum;
    int lowbit(int x)
    {
    return x&-x;
    }
    int add(ll v)
    {
    for(int x=sum;x;x-=lowbit(x))
        b[x]=mx(b[x],v);
    }
    int query(int pos)
    {
    ll ans=0;
    for(int x=sum-pos+1;x<=sum;x+=lowbit(x))
        ans=mx(ans,b[x]);
    return ans;
    }
    int main()
    {
    int m,p;
    char q;
    ll t=0;
    scanf("%d%lld",&m,&d);
    for(int i=1;i<=m;++i)
    {
        cin>>q;
        if(q=='A'){
            sum++;
            ll n;
            scanf("%lld",&n);
            add((n+t)%d);
        }
        else{
            scanf("%d",&p);
            t=query(p);
            printf("%lld\n",t);
        }
    }
    return 0;
    }

    写了快读居然没用上

原文地址:https://www.cnblogs.com/nishikino-curtis/p/8496732.html

时间: 2024-11-12 05:43:43

[洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?的相关文章

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

hdu1394(枚举/树状数组/线段树单点更新&amp;区间求和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数: 所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序: 代码: 1.直接暴力 1

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU 1166 敌兵布阵 (树状数组&#183;线段树)

题意  中文 动态区间和问题   只会更新点  最基础的树状数组 线段树的应用 树状数组代码 #include <bits/stdc++.h> using namespace std; const int N = 50005; int c[N], n, m; void add(int p, int x) { while(p <= n) c[p] += x, p += p & -p; } int getSum(int p) { int ret = 0; while(p > 0

Curious Robin Hood(树状数组+线段树)

1112 - Curious Robin Hood    PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 64 MB Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another tri

士兵杀敌(四)(树状数组+线段树)

士兵杀敌(四) 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来帮助小工吧. 假设起始时所有人的军功都是0. 输入

Color the ball(树状数组+线段树)

Color the ball Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 3   Accepted Submission(s) : 1 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b

Codeforces Round #225 (Div. 1) C 树状数组 || 线段树

看到这题很开心啊,有印象跟以前做过的很像,貌似最近就做过一个,以时间戳为区间来建立树状数组,然后一开始我以为题意是,给x点加val,它以下的所有节点都加-val:所以一开始就以 加 和 减 建立了两个树状数组,最后 减去就是答案,写完发现跟案例对不上啊,读了题目也没发现读错了,对于那句话 我理解错了,后来看了 这个: http://blog.csdn.net/keshuai19940722/article/details/18967661 仔细看看处理部分,我还以为分奇偶性有规律呢,后来才发现读

HDU 4417 Super Mario (树状数组/线段树)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble agai