Description
Solution
我們可以設一個樸素的DP
記表示第輪上一個人是否操作了i這個位置,當前先手-當前後手的權值的最大值。
顯然
容易得到轉移
邊界爲
容易發現一個性質
且這兩者的差似乎很有規律
記
代入上面的轉移
上面減下面
分類討論,若即,則
反之
容易看出
顯然可以從前往後建一個遞增的單調棧,用線段樹維護單調棧就能夠維護d了。
考慮計算答案。
一直推下去,可得
d的帶權和就用線段樹維護單調棧來做,s的就直接算。
時間複雜度
線段樹維護單調棧的具體實現參考代碼。
Code
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
const int N=200005;
typedef long long LL;
using namespace std;
LL sm[2*N],sp[2*N],mi[2*N],t[2*N][2];
int n,a[N],n1;
int tc(int x,int y)
{
if(((y-x)&1)||x>y) return 0;
else return (y&1)?-1:1;
}
int query(int k,int l,int r,int w,int v)
{
if(l==r)
{
if(mi[k]<v) return sm[k]+tc(l+1,w)*v;
else return tc(l,w)*v;
}
int mid=(l+r)>>1;
if(mi[t[k][1]]<=v) return sp[k]+query(t[k][1],mid+1,r,w,v);
else return query(t[k][0],l,mid,w,v);
}
void up(int k,int l,int r)
{
int mid=(l+r)>>1;
sp[k]=query(t[k][0],l,mid,mid,mi[t[k][1]]);
sm[k]=sm[t[k][1]]+sp[k];
mi[k]=min(mi[t[k][0]],mi[t[k][1]]);
}
void build(int k,int l,int r)
{
if(l==r) {mi[k]=2*a[l],sm[k]=(l&1)?-mi[k]:mi[k];return;}
int mid=(l+r)>>1;
build(t[k][0]=++n1,l,mid);
build(t[k][1]=++n1,mid+1,r);
up(k,l,r);
}
void modify(int k,int l,int r,int x,int v)
{
if(l==r) {mi[k]=v,sm[k]=(l&1)?-mi[k]:mi[k];return;}
int mid=(l+r)>>1;
if(x<=mid) modify(t[k][0],l,mid,x,v);
else modify(t[k][1],mid+1,r,x,v);
up(k,l,r);
}
int main()
{
cin>>n;
LL ans=0;
fo(i,1,n) scanf("%d",&a[i]),ans+=(i&1)?2*a[i]:0;
int q;
cin>>q;
n1=1;
build(1,2,n);
printf("%lld\n",(ans+sm[1])/2);
fo(t,1,q)
{
int x,y;
scanf("%d%d",&x,&y);
a[x]-=y;
ans-=(x&1)?2*y:0;
if(x!=1) modify(1,2,n,x,2*a[x]);
printf("%lld\n",(ans+sm[1])/2);
}
}