[bzoj3747][POI2015]Kinoman_線段樹
阿新 • • 發佈:2018-05-24
sans PE while down typedef 如果 區間 for max
Kinoman bzoj-3747 POI-2015
題目大意:有m部電影,第i部電影的好看值為w[i]。現在放了n天電影,請你選擇一段區間l~r使得l到r之間的好看值總和最大。特別地,如果同一種電影放了兩遍及以上,那麽這種電影的好看值將不會被獲得。
註釋:$1\le m \le n \le 10^6$。
想法:和rmq problem類似的,我們處理出每一個位置pos右邊第一個和pos上電影種類相同的位置nxt[pos]。然後,我從1-n掃一遍,每次講l+1到nxt[l]-1之間的值加上w[a[l]],這個過程可以用線段樹維護。
最後,附上醜陋的代碼... ...
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 1000050 #define lson pos<<1 #define rson pos<<1|1 typedef long long ll; ll t[N<<2],lazy[N<<2]; int f[N],w[N],nxt[N],n,m,now[N]; char nc() { static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int rd() { register int x=0; register char s=nc(); while(s<‘0‘||s>‘9‘)s=nc(); while(s>=‘0‘&&s<=‘9‘)x=(x<<3)+(x<<1)+s-‘0‘,s=nc(); return x; } void pushdown(int pos) { if(!lazy[pos]) return; ll d=lazy[pos]; lazy[lson]+=d; lazy[rson]+=d; t[lson]+=d; t[rson]+=d; lazy[pos]=0; } void update(int l,int r,int x,int y,ll v,int pos) { if(x<=l&&y>=r) { t[pos]+=v; lazy[pos]+=v; return; } pushdown(pos); int mid=(l+r)>>1; if(x<=mid) update(l,mid,x,y,v,lson); if(y>mid) update(mid+1,r,x,y,v,rson); t[pos]=max(t[lson],t[rson]); } int main() { n=rd(),m=rd(); for(int i=1;i<=n;i++) { f[i]=rd(); } for(int i=1;i<=m;i++) { w[i]=rd(); } for(int i=n;i;i--) { nxt[i]=now[f[i]]; now[f[i]]=i; } for(int i=1;i<=m;i++) { if(now[i]) { if(!nxt[now[i]]) update(1,n,now[i],n,w[i],1); else update(1,n,now[i],nxt[now[i]]-1,w[i],1); } } ll ans=0; for(int i=1;i<=n;i++) { ans=max(ans,t[1]); if(nxt[i]) { update(1,n,i,nxt[i]-1,-w[f[i]],1); if(nxt[nxt[i]]) update(1,n,nxt[i],nxt[nxt[i]]-1,w[f[i]],1); else update(1,n,nxt[i],n,w[f[i]],1); } else update(1,n,i,n,-w[f[i]],1); } printf("%lld\n",ans); return 0; }
小結:線段樹能幹好多事情啊qwq
[bzoj3747][POI2015]Kinoman_線段樹