bzoj 2482: [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行,每行两个数,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




Source

spoj gss2


枚举右端点。我们用线段树维护以这个点开始到当前点的ans和过去最大ans

然后离线回答询问即可

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct tree
{
     int l,r;
     long long m,vm;
     long long tag,vtag;
}tr[800001];
struct que
{
     int l,r;
     int p;
     long long ans;
}ask[100001];
inline bool cmp1(que x,que y)
{
     if(x.r<y.r)
          return true;
     return false;
}
inline bool cmp2(que x,que y)
{
     if(x.p<y.p)
          return true;
     return false;
}
inline void up(int p)
{
     tr[p].m=max(tr[p*2].m,tr[p*2+1].m);
     tr[p].vm=max(tr[p*2].vm,tr[p*2+1].vm);
}
inline void push(int p)
{
     tr[p*2].vm=max(tr[p*2].vm,tr[p*2].m+tr[p].vtag);
     tr[p*2+1].vm=max(tr[p*2+1].vm,tr[p*2+1].m+tr[p].vtag);
     tr[p*2].m+=tr[p].tag;
     tr[p*2+1].m+=tr[p].tag;
     
     tr[p*2].vtag=max(tr[p*2].vtag,tr[p*2].tag+tr[p].vtag);
     tr[p*2+1].vtag=max(tr[p*2+1].vtag,tr[p*2+1].tag+tr[p].vtag);
     tr[p*2].tag+=tr[p].tag;
     tr[p*2+1].tag+=tr[p].tag;
     tr[p].tag=0;
     tr[p].vtag=0;
}
inline void build(int p,int l,int r)
{
     tr[p].l=l;
     tr[p].r=r;
     if(l!=r)
     {
     	  int mid=(l+r)/2;
     	  build(p*2,l,mid);
     	  build(p*2+1,mid+1,r);
          up(p);
     }
}
inline void add(int p,int l,int r,long long x)
{
	 if(l>r)
	      return ;
	/* if(l==0)
	      l=1;*/
     if(l<=tr[p].l&&tr[p].r<=r)
     {
          tr[p].m+=x;
          tr[p].tag+=x;
          tr[p].vm=max(tr[p].vm,tr[p].m);
          tr[p].vtag=max(tr[p].vtag,tr[p].tag);
     }
     else
     {
          push(p);
          int mid=(tr[p].l+tr[p].r)/2;
          if(l<=mid)
               add(p*2,l,r,x);
          if(r>mid)
               add(p*2+1,l,r,x);
          up(p);
     }
}
inline long long askx(int p,int l,int r)
{
     if(l<=tr[p].l&&tr[p].r<=r)
          return tr[p].vm;
     else
     {
          push(p);
          int mid=(tr[p].l+tr[p].r)/2;
          long long ans=0;
          if(l<=mid)
               ans=max(ans,askx(p*2,l,r));
          if(r>mid)
               ans=max(ans,askx(p*2+1,l,r));
          return ans;
     }
}
int a[1000001];
int pre[1000001],la[1000001];
int main()
{
//	 freopen("sequence.in","r",stdin); 
//	 freopen("sequence.out","w",stdout);
     int n;
     scanf("%d",&n);
     int i;
     for(i=1;i<=n;i++)
          scanf("%d",&a[i]);
     for(i=1;i<=n;i++)
     {
     	  pre[i]=la[a[i]];
          la[a[i]]=i;
     }
     build(1,1,n);
     int m;
     scanf("%d",&m);
     for(i=1;i<=m;i++)
     {
     	  scanf("%d%d",&ask[i].l,&ask[i].r);
          ask[i].p=i;
     }
     sort(ask+1,ask+1+m,cmp1);
     int d=1;
     for(i=1;i<=n;i++)
     {
          add(1,pre[i]+1,i,a[i]);
          while(d<=m&&ask[d].r==i)
          {
               ask[d].ans=askx(1,ask[d].l,ask[d].r);
               d++;
          }
     }
     sort(ask+1,ask+1+m,cmp2);
     for(i=1;i<=m;i++)
          printf("%lld\n",ask[i].ans);
     return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值