bzoj 2006 [NOI2010]超级钢琴——ST表+堆
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2006
每个右端点的左端点在一个区间内;用堆记录端点位置、可选区间,按价值排序;拿出一个后也许分裂成两个。
第一次写了ST表,写得巨复杂,记录向前/后的最小值和位置,还为了预处理,又记 2^j 走到哪;调了半天边界,最后发现是Lg写错了!至今仍不知那样写为什么会错……
看看别人的代码,原来不用记两个方向的,用的时候往前跳几步再用向后的就行!也不用记录最小值,只要记录位置就行了;也不用记录 to[ ][ ] ,只要从 i+2^j 有没有超过n就能判断边界。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long using namespace std; const int N=5e5+5,Lm=20; int n,m,L,R,a[N],s[N],Lg[N],stp[N][Lm+5],stn[N][Lm+5],to[N][Lm+5]; int idp[N][Lm+5],idn[N][Lm+5]; ll ans; struct Node{ int ps,to,l,r,v; Node(int p,int t,int l,int r,int v):ps(p),to(t),l(l),r(r),v(v) {} bool operator< (const Node &b) const {return v<b.v;} }; priority_queue<Node> q; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return fx?ret:-ret; } void init() { /* int i=1,cd=0,nxt; for(;i<=n;i=nxt,cd++) { nxt=i<<1; for(int j=i;j<nxt&&j<=n;j++) Lg[j]=cd; } i>>=1; for(;i<=n;i++) Lg[i]=cd; */ for(int i=2;i<=n;i++) Lg[i]=Lg[i>>1]+1; memset(to,0x3f,sizeof to);// for(int i=0;i<n;i++) { stp[i][0]=s[i]; idp[i][0]=i; to[i][0]=i-1; for(int j=1,d;j<=Lm;j++) { d=to[i][j-1]; if(d<0||to[d][j-1]>n)break;// >n!!! //if d<0 to[i][j]=to[d][j-1]; if(stp[d][j-1]<stp[i][j-1]) { stp[i][j]=stp[d][j-1]; idp[i][j]=idp[d][j-1]; } else { stp[i][j]=stp[i][j-1]; idp[i][j]=idp[i][j-1]; } } } memset(to,0x3f,sizeof to); for(int i=n-1;i>=0;i--) { stn[i][0]=s[i]; idn[i][0]=i; to[i][0]=i+1; for(int j=1,d;j<=Lm;j++) { d=to[i][j-1]; if(to[d][j-1]>n)break; to[i][j]=to[d][j-1]; if(stn[d][j-1]<stn[i][j-1]) { stn[i][j]=stn[d][j-1]; idn[i][j]=idn[d][j-1]; } else { stn[i][j]=stn[i][j-1]; idn[i][j]=idn[i][j-1]; } } } } int main() { n=rdn(); m=rdn(); L=rdn(); R=rdn(); for(int i=1;i<=n;i++) a[i]=rdn(),s[i]=s[i-1]+a[i]; init(); for(int i=1,d,t;i<=n;i++) { int l=i-R,r=i-L;//not +1 if(r<0) continue; l=max(l,0); t=Lg[r-l+1];//not +1 d=(stp[r][t]<stn[l][t]?idp[r][t]:idn[l][t]); q.push(Node(i,d,l,r,s[i]-s[d])); } while(m--) { Node k=q.top(); q.pop(); ans+=k.v; int l1=k.l,r1=k.to-1, l2=k.to+1,r2=k.r; int t,d; if(l1<=r1) { t=Lg[r1-l1+1]; d=(stp[r1][t]<stn[l1][t]?idp[r1][t]:idn[l1][t]); q.push(Node(k.ps,d,l1,r1,s[k.ps]-s[d])); } if(l2<=r2) { t=Lg[r2-l2+1]; d=(stp[r2][t]<stn[l2][t]?idp[r2][t]:idn[l2][t]); q.push(Node(k.ps,d,l2,r2,s[k.ps]-s[d])); } } printf("%lld\n",ans); return 0; }