题意:每次破坏一个数 求当前连续区间和最大的那个值是多少
思路:因为每个数都大于0 所以只要记录每个区间最右边的数的和 就可以了 每次破坏都有可能会产生两个区间 所以只要判断一下就可以了
ps:其实用stl的lowerbound 会更方便 结果写了三个线段树
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;
#define N 100100
#define LL long long
LL sum[N];
int a[N];
LL c[N*4];
int v1[N*4];
int v2[N*4];
int vis[N];
int n;
void build(int l,int r,int tt)
{
if(l==r)
{
v2[tt]=n+1;
return ;
}
int mid=(l+r)/2;
build(l,mid,tt*2);
build(mid+1,r,tt*2+1);
v2[tt]=min(v2[tt*2],v2[tt*2+1]);
}
void updatev(int l,int r,int k,int tt)
{
if(l==r)
{
v1[tt]=k;
v2[tt]=k;
return ;
}
int mid=(l+r)/2;
if(mid<k)
{
updatev(mid+1,r,k,tt*2+1);
}
else
{
updatev(l,mid,k,tt*2);
}
v1[tt]=max(v1[tt*2],v1[tt*2+1]);
v2[tt]=min(v2[tt*2],v2[tt*2+1]);
}
int queryl(int l,int r,int tt,int x,int y)
{
if(l==x&&r==y)
{
return v1[tt];
}
int mid=(l+r)/2;
if(mid<x)
{
return queryl(mid+1,r,tt*2+1,x,y);
}
else if(y<=mid)
{
return queryl(l,mid,tt*2,x,y);
}
else
return max(queryl(l,mid,tt*2,x,mid),queryl(mid+1,r,tt*2+1,mid+1,y));
}
int queryr(int l,int r,int tt,int x,int y)
{
if(l==x&&r==y)
{
return v2[tt];
}
int mid=(l+r)/2;
if(mid<x)
{
return queryr(mid+1,r,tt*2+1,x,y);
}
else if(y<=mid)
{
return queryr(l,mid,tt*2,x,y);
}
else
return min(queryr(l,mid,tt*2,x,mid),queryr(mid+1,r,tt*2+1,mid+1,y));
}
void update(int l,int r,int k,int tt,LL x)
{
if(l==r)
{
c[tt]=x;
return ;
}
int mid=(l+r)/2;
if(mid<k)
{
update(mid+1,r,k,tt*2+1,x);
}
else
{
update(l,mid,k,tt*2,x);
}
c[tt]=max(c[tt*2],c[tt*2+1]);
}
int main()
{
int x;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
build(1,n,1);
update(1,n,n,1,sum[n]);
int pos;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
update(1,n,x,1,0);
updatev(1,n,x,1);
if(x>1)
{
pos=queryl(1,n,1,1,x-1);
if(pos!=x-1)
{
update(1,n,x-1,1,sum[x-1]-sum[pos]);
}
}
if(x<n)
{
pos=queryr(1,n,1,x+1,n);
if(pos!=x+1)
{
update(1,n,pos-1,1,sum[pos-1]-sum[x]);
}
}
printf("%lld\n",c[1]);
}
return 0;
}