1. 程式人生 > >luogu 3582 線段樹

luogu 3582 線段樹

digi div 線段樹 \n clas pen int query esp

線段樹內存下mx[k]的值是動態的1-i這個區間的貢獻答案

實際上點存的就是區間答案,但用max是為了求最大區間答案(有可能雖然貢獻被消除但後來有更大的貢獻填補答案空缺)

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
#define LL long long
#define In freopen("7.in","r",stdin)
#define In2 freopen("8.in","r",stdin)
using
namespace std; const int N=1e6+50; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch==-)f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} int n,m,w[N],f[N],mark[N],pre[N]; LL mx[N<<2],tag[N<<2
],ans=0; inline void pushup(int k){ mx[k]=max(mx[k<<1],mx[k<<1|1]);} inline void pushdown(int k,int l,int r,int mid){ if(l==r) return; LL v=tag[k];tag[k]=0; tag[k<<1]+=v;mx[k<<1]+=v; tag[k<<1|1]+=v;mx[k<<1|1]+=v;} inline void change(int k,int l,int
r,int x,int y,LL d){ if(x<=l&&r<=y){ tag[k]+=d;mx[k]+=d;return;} int mid=(l+r)>>1; if(tag[k]) pushdown(k,l,r,mid); if(x<=mid) change(k<<1,l,mid,x,y,d); if(mid<y) change(k<<1|1,mid+1,r,x,y,d); pushup(k); } inline LL query(int k,int l,int r,int x,int y){ if(x<=l&&r<=y) return mx[k];LL res=0; int mid=(l+r)>>1;if(tag[k])pushdown(k,l,r,mid); if(x<=mid) res=max(res,query(k<<1,l,mid,x,y)); if(mid<y) res=max(res,query(k<<1|1,mid+1,r,x,y)); return mx[k];} int main(){ n=read();m=read(); rep(i,1,n) f[i]=read(); rep(i,1,m) w[i]=read(); rep(i,1,n) pre[i]=mark[f[i]],mark[f[i]]=i; rep(i,1,n){ change(1,1,n,pre[i]+1,i,w[f[i]]); if(pre[i]) change(1,1,n,pre[pre[i]]+1,pre[i],-w[f[i]]); ans=max(ans,query(1,1,n,1,i)); } printf("%lld\n",ans);return 0; }

luogu 3582 線段樹