zoukankan      html  css  js  c++  java
  • bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

    2482: [Spoj1557] Can you answer these queries II

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 145  Solved: 76
    [Submit][Status][Discuss]

    Description

    给定n个元素的序列。
    给出m个询问:求l[i]~r[i]的最大子段和(可选空子段)。
    这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次。
    比如:1,2,3,2,2,2出现了3次,但只算一次,于是这个序列的和是1+2+3=6。

    Input

     

    第一行一个数n。
    第二行n个数,为给定的序列,这些数的绝对值小于等于100000。
    第三行一个数m。
    接下来m行,每行两个数,l[i],r[i]。

    Output

    M行,每行一个数,为每个询问的答案。

    Sample Input

    9
    4 -2 -2 3 -1 -4 2 2 -6
    3
    1 2
    1 5
    4 9


    Sample Output


    4
    5
    3

    HINT

    【数据说明】

    30%:1 <= n, m <= 100

    100%:1 <= n, m <= 100000

      一年前抄标程把spoj的gss2做了,一年后重新做了一遍,仍然把我恶心的。。。。【话说这道题没卡longlong很不爽】

      还是一步一步想吧,首先是离线,转成线段树的区间加,询问区间最大值的历史最大值。

      这东西怎么搞呢?

      我们先不考虑下放标记的问题,单考虑一个结点。

      记录plus[]表示从上次清除tag到现在,已经有多少“加”操作下降到当前点。

      记录hplus[]表示从上次清除tag到现在,历史加操作“峰值”与plus的差值。

      在不考虑下放的情况下每次加v操作及plus+=v,hplus=max(0,hplus-v);

      当然作为线段树,我们还要记录maxv表示当前区间的答案,及区间历史最大值。

      然后再考虑标记下方问题。

      在调试中发现单纯maxv很难维护,需要在加一个中间变量,视为nmaxv,及当前最大值。

      转移什么的知道变量含义就可以参考代码了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<assert.h>
    using namespace std;
    #define MAXN 110000
    #define MAXQ MAXN
    #define MAXT MAXN*5
    #define lch (now<<1)
    #define rch (now<<1^1)
    #define smid ((l+r)>>1)
    #define INF 0x3f3f3f3f
    typedef long long qword;
    struct sgt_node
    {
            qword plus,maxv;
            qword hplus;
            qword nmaxv;
    }sgt[MAXT];
    void make_plus(int now,qword v)
    {
            sgt[now].hplus-=v;
            sgt[now].plus+=v;
            sgt[now].hplus=max(sgt[now].hplus,0ll);
            sgt[now].nmaxv+=v;
            sgt[now].maxv=max(sgt[now].maxv,sgt[now].nmaxv+sgt[now].hplus);
    }
    void down(int now)
    {
            make_plus(lch,sgt[now].plus+sgt[now].hplus);
            make_plus(lch,-sgt[now].hplus);
            make_plus(rch,sgt[now].plus+sgt[now].hplus);
            make_plus(rch,-sgt[now].hplus);
            sgt[now].plus=sgt[now].hplus=0;
            assert(sgt[now].maxv==max(sgt[lch].maxv,sgt[rch].maxv));
    }
    void Build_sgt(int now,int l,int r)
    {
            sgt[now].plus=0;
            sgt[now].hplus=0;
            sgt[now].maxv=0;
            if (l==r)return ;
            Build_sgt(lch,l,smid);
            Build_sgt(rch,smid+1,r);
    }
    void Add_sgt(int now,int l,int r,int x,int y,qword v)
    {
            if (l==x && r==y)
            {
                    make_plus(now,v);
                    return ;
            }
            down(now);
            if (y<=smid)
                    Add_sgt(lch,l,smid,x,y,v);
            else if (smid<x)
                    Add_sgt(rch,smid+1,r,x,y,v);
            else 
            {
                    Add_sgt(lch,l,smid,x,smid,v);
                    Add_sgt(rch,smid+1,r,smid+1,y,v);
            }
            sgt[now].nmaxv=max(sgt[lch].nmaxv,sgt[rch].nmaxv);
            sgt[now].maxv=max(sgt[lch].maxv,sgt[rch].maxv);
    }
    qword Query_sgt(int now,int l,int r,int pos)
    {
            if (l==r)
                    return sgt[now].maxv+sgt[now].plus+sgt[now].hplus;
            down(now);
            if (pos<=smid)
                    return Query_sgt(lch,l,smid,pos);
            else 
                    return Query_sgt(rch,smid+1,r,pos);
    }
    int Query_sgt(int now,int l,int r,int x,int y)
    {
            if (l==x && r==y)
                    return sgt[now].maxv;
            down(now);
            if (y<=smid)
                    return Query_sgt(lch,l,smid,x,y);
            else if (smid<x)
                    return Query_sgt(rch,smid+1,r,x,y);
            else
                    return max(Query_sgt(lch,l,smid,x,smid),Query_sgt(rch,smid+1,r,smid+1,y));
    }
    int a[MAXN],lastid[MAXN*2],prv[MAXN];
    struct qur_t
    {
            int l,r,id;
            qword ans;
    }qur[MAXQ];
    bool cmp_r(qur_t q1,qur_t q2)
    {
            return q1.r<q2.r;
    }
    bool cmp_id(qur_t q1,qur_t q2)
    {
            return q1.id<q2.id;
    }
    int main()
    {
            freopen("input.txt","r",stdin);
    //        freopen("output.txt","w",stdout);
            int n,m;
            scanf("%d",&n);
            for (int i=1;i<=n;i++)
            {
                    scanf("%d",a+i);
                    prv[i]=lastid[a[i]+MAXN];
                    lastid[a[i]+MAXN]=i;
            }
            scanf("%d",&m);
            for (int i=0;i<m;i++)
            {
                    scanf("%d%d",&qur[i].l,&qur[i].r);
                    qur[i].id=i;
            }
            sort(qur,qur+m,cmp_r);
            int qn=0;
            for (int i=1;i<=n;i++)
            {
                //    fprintf(stderr,"%d
    ",i);
                    Add_sgt(1,1,n,prv[i]+1,i,a[i]);
                    while (qn<m && qur[qn].r==i)
                    {
                            qur[qn].ans=Query_sgt(1,1,n,qur[qn].l,qur[qn].r);
                            qn++;
                    }
            }
            sort(qur,qur+m,cmp_id);
            for (int i=0;i<m;i++)
                    printf("%lld
    ",qur[i].ans);
    }
  • 相关阅读:
    Panorama和Pivot的区别
    Windows phone 全景视图
    在usercontrol里实现导航
    (App.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
    Windows phone重写返回键
    Windows Phone 8弹窗
    Kotlin 区间的一些小注意
    Kotlin 区间和循环 Loop和Range
    Kotlin when 流程判断
    Kotlin 在kotlin内使用Java的一些注意(长篇)
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4442736.html
Copyright © 2011-2022 走看看