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\n",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\n",qur[i].ans);
}
时间: 2024-10-04 06:31:22

bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树的相关文章

SPOJ 1557. Can you answer these queries II 线段树

Can you answer these queries II Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://www.spoj.com/problems/GSS2/ Description Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse

Spoj 1557 Can you answer these queries II 线段树 任意区间最大子段和 不重复数字

题目链接:点击打开链接 每个点都是最大值,把一整个序列和都压缩在一个点里. #include <vector> #include <iostream> #include <algorithm> #include <string.h> #include <stdio.h> using namespace std; #define N 100005 #define Lson(x) (x<<1) #define Rson(x) (x<

spoj gss2 : Can you answer these queries II 离线&amp;&amp;线段树

1557. Can you answer these queries II Problem code: GSS2 Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse to write two program of same kind at all. So he always failes in co

SPOJ GSS3 Can you answer these queries III (线段树)

题目大意: 求区间最大子区间的和. 思路分析: 记录左最大,右最大,区间最大. 注意Q_L  和 Q_R  就好. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 55555 using na

SPOJ GSS4 Can you answer these queries IV (线段树)

题目大意: 给出N个数 0     操作   把 l -----  r之间的数全部开平方 1     操作  输出 l -----r  之间的和 思路分析: 判断区间里的数字是否全相同.如果相同, 将cov 置为该数 查询的时候和更新的时候,如果碰到cov != -1 的  就直接返回就可以了 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #incl

SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)

GSS2 - Can you answer these queries II #tree Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse to write two program of same kind at all. So he always failes in contests. When

【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树

[BZOJ2482][Spoj1557] Can you answer these queries II Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,于是这个序列的和是1+2+3=6. Input 第一行一个数n. 第二行n个数,为给定的序列,这些数的绝对值小于等于100000. 第三行一个数m. 接下来m行,每行两个

SPOJ GSS2 Can you answer these queries II

Time Limit: 1000MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Description Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse to write two program of same kind at

SPOJ GSS5 Can you answer these queries V ——线段树

[题目分析] GSS1上增加区间左右端点的限制. 直接分类讨论就好了. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #i