bzoj 2006 超级钢琴 —— ST表
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2006
本来应该是可以用主席树,找区间最小值,取出来后再找那段区间的次小值......
但也可以只找最小值,取出来后把原来区间分裂成两个,继续找最小值,用ST表即可;
发现自己还没写过 ST 表囧...
思路同这里:https://www.cnblogs.com/CQzhangyu/p/7071394.html
自己写了半天,才10分...奋力改了改,那个 find 里面 r++ 而 l 不 ++ 的细节真奇妙...
然后就50分了...
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int const xn=5e5+5,inf=0x3f3f3f3f; int n,k,L,R,t[xn],lg[xn],f[xn][25],id[xn][25],bin[25],ans; struct N{ int a,b,l,r; bool operator < (const N &y) const {return t[b]-t[a]<t[y.b]-t[y.a];} }; priority_queue<N>q; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } void find(int l,int r,int &y) { int g=lg[r-l+1];// r++;//!!!!! // printf("id[%d][%d]=%d\n",l,g,id[l][g]); if(t[id[r][g]]<t[id[l+bin[g]][g]])y=id[r][g]; else y=id[l+bin[g]][g]; // printf("find(%d,%d)=%d\n",l,r,y); } int main() { n=rd(); k=rd(); L=rd(); R=rd(); bin[0]=1; for(int i=1,x;i<=n;i++)x=rd(),t[i]=t[i-1]+x; for(int i=1,p,lst=1;i<=n;i++) { if(i<lst*2)lg[i]=lg[i-1]; else lg[i]=lg[i-1]+1,lst*=2,bin[lg[i]]=lst; id[i][0]=i-1; f[i][0]=i-1; for(int j=1;j<=20;j++) { f[i][j]=f[f[i][j-1]][j-1]; if(t[id[i][j-1]]<t[id[f[i][j-1]][j-1]])id[i][j]=id[i][j-1]; else id[i][j]=id[f[i][j-1]][j-1]; } int l=max(i-R,0),r=i-L,len=r-l+1; if(l>r)continue; find(l,r,p); q.push((N){p,i,l,r}); // printf("ps:%d,%d\n",p,i); } int cnt=0,p; while(cnt<k) { int a=q.top().a,b=q.top().b,l=q.top().l,r=q.top().r; q.pop(); if(l<=a-1)find(l,a-1,p),q.push((N){p,b,l,a-1})/*,printf("ps:%d,%d\n",p,b)*/; if(a+1<=r)find(a+1,r,p),q.push((N){p,b,a+1,r})/*,printf("ps:%d,%d\n",p,b)*/; cnt++; ans+=t[b]-t[a]; // printf("a=%d b=%d\n",a,b); } printf("%d\n",ans); return 0; }
最后发现把 ans 改成 long long 就A了!!!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int const xn=5e5+5,inf=0x3f3f3f3f; int n,k,L,R,t[xn],lg[xn],f[xn][25],id[xn][25],bin[25]; long long ans; struct N{ int a,b,l,r; bool operator < (const N &y) const {return t[b]-t[a]<t[y.b]-t[y.a];} }; priority_queue<N>q; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } void find(int l,int r,int &y) { int g=lg[r-l+1];// r++;//!!!!! // printf("id[%d][%d]=%d\n",l,g,id[l][g]); if(t[id[r][g]]<t[id[l+bin[g]][g]])y=id[r][g]; else y=id[l+bin[g]][g]; // printf("find(%d,%d)=%d\n",l,r,y); } int main() { n=rd(); k=rd(); L=rd(); R=rd(); bin[0]=1; for(int i=1,x;i<=n;i++)x=rd(),t[i]=t[i-1]+x; for(int i=1,p,lst=1;i<=n;i++) { if(i<lst*2)lg[i]=lg[i-1]; else lg[i]=lg[i-1]+1,lst*=2,bin[lg[i]]=lst; id[i][0]=i-1; f[i][0]=i-1; for(int j=1;j<=20;j++) { f[i][j]=f[f[i][j-1]][j-1]; if(t[id[i][j-1]]<t[id[f[i][j-1]][j-1]])id[i][j]=id[i][j-1]; else id[i][j]=id[f[i][j-1]][j-1]; } int l=max(i-R,0),r=i-L,len=r-l+1; if(l>r)continue; find(l,r,p); q.push((N){p,i,l,r}); // printf("ps:%d,%d\n",p,i); } int cnt=0,p; while(cnt<k) { int a=q.top().a,b=q.top().b,l=q.top().l,r=q.top().r; q.pop(); if(l<=a-1)find(l,a-1,p),q.push((N){p,b,l,a-1})/*,printf("ps:%d,%d\n",p,b)*/; if(a+1<=r)find(a+1,r,p),q.push((N){p,b,a+1,r})/*,printf("ps:%d,%d\n",p,b)*/; cnt++; ans+=t[b]-t[a]; // printf("a=%d b=%d\n",a,b); } printf("%lld\n",ans); return 0; }
但已经模仿了TJ啦...处理的时候果然要带上自己,不然各种不方便...
别忘了开 long long !因为是多段区间的和!
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int const xn=5e5+5,inf=0x3f3f3f3f; int n,k,L,R,t[xn],lg[xn],id[xn][25]; long long ans; struct N{ int a,b,l,r; bool operator < (const N &y) const {return t[b]-t[a]<t[y.b]-t[y.a];} }; priority_queue<N>q; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } int mn(int a,int b){return t[a]<t[b]?a:b;} int find(int l,int r) { if(l>r)return -1; int g=lg[r-l+1]; return mn(id[l][g],id[r-(1<<g)+1][g]); } int main() { n=rd(); k=rd(); L=rd(); R=rd(); for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1; for(int i=1,x;i<=n;i++)x=rd(),t[i]=t[i-1]+x,id[i][0]=i;// for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<=n;i++)//0 //-1 id[i][j]=mn(id[i][j-1],id[i+(1<<(j-1))][j-1]); for(int i=L;i<=n;i++)q.push((N){find(max(i-R,0),i-L),i,max(i-R,0),i-L}); int cnt=0,p; while(cnt<k) { int a=q.top().a,b=q.top().b,l=q.top().l,r=q.top().r; q.pop(); cnt++; ans+=t[b]-t[a]; int c=find(l,a-1),d=find(a+1,r); if(c!=-1)q.push((N){c,b,l,a-1}); if(d!=-1)q.push((N){d,b,a+1,r}); } printf("%lld\n",ans); return 0; }