bzoj 4504: K個串【大根堆+主席樹】
阿新 • • 發佈:2019-04-05
clu || turn oot 每次 make getc tor cst
像超級鋼琴一樣把五元組放進大根堆,每次取一個出來拆開,(d,l,r,p,v)表示右端點為d,左端點區間為(l,r),最大區間和值為v左端點在p上
關於怎麽快速求區間和,用可持久化線段樹維護(主席樹?)每個點到他root的區間和,這樣每次右端點右移就是上一個的線段樹在(la[a[i]]+1,i)加上a[i],la是這個值a[i]上一次出現的位置
然後就可以在線處理詢問了
有一點因為這個線段樹建的是1~n,所以右端點不是n的時候取max會取到右端點向右還是初始值0的位置(有可能前面是負數),這樣的解決方法就是先全填成-inf,然後每次右移的時候先把右端點加上inf再處理區間加
#include<iostream> #include<cstdio> #include<algorithm> #include<map> #include<queue> using namespace std; const int N=300005; int n,m,has,rt[N],tot,la[N]; long long a[N],g[N],rl[N],ans; map<long long ,int>mp; struct zxs { int ls,rs,p; long long mx,lz; }t[7000005]; struct qwe { int d,l,r,p; long long v; qwe(int D=0,int L=0,int R=0,int P=0,long long V=0) { d=D,l=L,r=R,p=P,v=V; } bool operator < (const qwe &a) const { return v<a.v; } }; priority_queue<qwe>q; int read() { int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(p=='-') f=-1; p=getchar(); } while(p>='0'&&p<='9') { r=r*10+p-48; p=getchar(); } return r*f; } void build(int &ro,int l,int r) { ro=++tot; t[ro].p=l,t[ro].mx=-1e15; if(l==r) return; int mid=(l+r)>>1; build(t[ro].ls,l,mid); build(t[ro].rs,mid+1,r); } void ud(int ro) { if(t[t[ro].ls].mx>t[t[ro].rs].mx) t[ro].mx=t[t[ro].ls].mx,t[ro].p=t[t[ro].ls].p; else t[ro].mx=t[t[ro].rs].mx,t[ro].p=t[t[ro].rs].p; } void update(int &ro,int la,int l,int r,int ll,int rr,long long v,long long lz) { ro=++tot; t[ro]=t[la]; t[ro].lz+=lz; t[ro].mx+=lz; if(l==ll&&r==rr) { t[ro].lz+=v; t[ro].mx+=v; return; } int mid=(l+r)>>1; if(t[ro].lz) { if(rr<=mid) { t[ro].rs=++tot; t[t[ro].rs]=t[t[la].rs]; t[t[ro].rs].mx+=t[ro].lz; t[t[ro].rs].lz+=t[ro].lz; update(t[ro].ls,t[la].ls,l,mid,ll,rr,v,t[ro].lz); } else if(ll>mid) { t[ro].ls=++tot; t[t[ro].ls]=t[t[la].ls]; t[t[ro].ls].mx+=t[ro].lz; t[t[ro].ls].lz+=t[ro].lz; update(t[ro].rs,t[la].rs,mid+1,r,ll,rr,v,t[ro].lz); } else { update(t[ro].ls,t[la].ls,l,mid,ll,mid,v,t[ro].lz); update(t[ro].rs,t[la].rs,mid+1,r,mid+1,rr,v,t[ro].lz); } t[ro].lz=0; } else { if(rr<=mid) update(t[ro].ls,t[la].ls,l,mid,ll,rr,v,0); else if(ll>mid) update(t[ro].rs,t[la].rs,mid+1,r,ll,rr,v,0); else { update(t[ro].ls,t[la].ls,l,mid,ll,mid,v,0); update(t[ro].rs,t[la].rs,mid+1,r,mid+1,rr,v,0); } } ud(ro); } pair<long long,int> ques(int ro,int l,int r,int ll,int rr) {//cerr<<l<<" "<<r<<" "<<ll<<" "<<rr<<endl; if(l==ll&&r==rr) return make_pair(t[ro].mx,t[ro].p); if(t[ro].lz) { t[tot+1]=t[t[ro].ls]; t[tot+1].mx+=t[ro].lz; t[tot+1].lz+=t[ro].lz; t[ro].ls=tot+1; t[tot+2]=t[t[ro].rs]; t[tot+2].mx+=t[ro].lz; t[tot+2].lz+=t[ro].lz; t[ro].rs=tot+2; tot+=2; t[ro].lz=0; } int mid=(l+r)>>1; if(rr<=mid) return ques(t[ro].ls,l,mid,ll,rr); else if(ll>mid) return ques(t[ro].rs,mid+1,r,ll,rr); else { pair<long long,int>a=ques(t[ro].ls,l,mid,ll,mid),b=ques(t[ro].rs,mid+1,r,mid+1,rr); return (a.first>b.first)?a:b; } } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) a[i]=g[i]=read(); sort(g+1,g+1+n); for(int i=1;i<=n;i++) if(i==1||g[i]!=g[i-1]) mp[g[i]]=++has,rl[has]=g[i]; build(rt[0],1,n); for(int i=1;i<=n;i++) { update(rt[i],rt[i-1],1,n,i,i,1e15,0); update(rt[i],rt[i],1,n,la[mp[a[i]]]+1,i,a[i],0); la[mp[a[i]]]=i;//cerr<<"OK"<<endl; } for(int i=1;i<=n;i++) q.push(qwe(i,1,i,t[rt[i]].p,t[rt[i]].mx)); while(m--) { qwe u=q.top(); q.pop(); ans=u.v;//cerr<<ans<<endl; if(u.l<=u.p-1) { pair<long long,int>nw=ques(rt[u.d],1,n,u.l,u.p-1); q.push(qwe(u.d,u.l,u.p-1,nw.second,nw.first)); } if(u.p+1<=u.r) { pair<long long,int>nw=ques(rt[u.d],1,n,u.p+1,u.r); q.push(qwe(u.d,u.p+1,u.r,nw.second,nw.first)); } } printf("%lld\n",ans); return 0; }
bzoj 4504: K個串【大根堆+主席樹】