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+,inf=0x3f3f3f3f;
int n,k,L,R,t[xn],lg[xn],f[xn][],id[xn][],bin[],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=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return f?ret:-ret;
}
void find(int l,int r,int &y)
{
int g=lg[r-l+];//
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[]=;
for(int i=,x;i<=n;i++)x=rd(),t[i]=t[i-]+x;
for(int i=,p,lst=;i<=n;i++)
{
if(i<lst*)lg[i]=lg[i-];
else lg[i]=lg[i-]+,lst*=,bin[lg[i]]=lst; id[i][]=i-; f[i][]=i-;
for(int j=;j<=;j++)
{
f[i][j]=f[f[i][j-]][j-];
if(t[id[i][j-]]<t[id[f[i][j-]][j-]])id[i][j]=id[i][j-];
else id[i][j]=id[f[i][j-]][j-];
} int l=max(i-R,),r=i-L,len=r-l+;
if(l>r)continue;
find(l,r,p); q.push((N){p,i,l,r});
// printf("ps:%d,%d\n",p,i);
}
int cnt=,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-)find(l,a-,p),q.push((N){p,b,l,a-})/*,printf("ps:%d,%d\n",p,b)*/;
if(a+<=r)find(a+,r,p),q.push((N){p,b,a+,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 ;
}
囧
最后发现把 ans 改成 long long 就A了!!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const xn=5e5+,inf=0x3f3f3f3f;
int n,k,L,R,t[xn],lg[xn],f[xn][],id[xn][],bin[];
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=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return f?ret:-ret;
}
void find(int l,int r,int &y)
{
int g=lg[r-l+];//
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[]=;
for(int i=,x;i<=n;i++)x=rd(),t[i]=t[i-]+x;
for(int i=,p,lst=;i<=n;i++)
{
if(i<lst*)lg[i]=lg[i-];
else lg[i]=lg[i-]+,lst*=,bin[lg[i]]=lst; id[i][]=i-; f[i][]=i-;
for(int j=;j<=;j++)
{
f[i][j]=f[f[i][j-]][j-];
if(t[id[i][j-]]<t[id[f[i][j-]][j-]])id[i][j]=id[i][j-];
else id[i][j]=id[f[i][j-]][j-];
} int l=max(i-R,),r=i-L,len=r-l+;
if(l>r)continue;
find(l,r,p); q.push((N){p,i,l,r});
// printf("ps:%d,%d\n",p,i);
}
int cnt=,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-)find(l,a-,p),q.push((N){p,b,l,a-})/*,printf("ps:%d,%d\n",p,b)*/;
if(a+<=r)find(a+,r,p),q.push((N){p,b,a+,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 ;
}
A
但已经模仿了TJ啦...处理的时候果然要带上自己,不然各种不方便...
别忘了开 long long !因为是多段区间的和!
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const xn=5e5+,inf=0x3f3f3f3f;
int n,k,L,R,t[xn],lg[xn],id[xn][];
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=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',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 -;
int g=lg[r-l+];
return mn(id[l][g],id[r-(<<g)+][g]);
}
int main()
{
n=rd(); k=rd(); L=rd(); R=rd();
for(int i=;i<=n;i++)lg[i]=lg[i>>]+;
for(int i=,x;i<=n;i++)x=rd(),t[i]=t[i-]+x,id[i][]=i;//
for(int j=;(<<j)<=n;j++)
for(int i=;i+(<<j)-<=n;i++)//0 //-1
id[i][j]=mn(id[i][j-],id[i+(<<(j-))][j-]);
for(int i=L;i<=n;i++)q.push((N){find(max(i-R,),i-L),i,max(i-R,),i-L});
int cnt=,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-),d=find(a+,r);
if(c!=-)q.push((N){c,b,l,a-});
if(d!=-)q.push((N){d,b,a+,r});
}
printf("%lld\n",ans);
return ;
}
bzoj 2006 超级钢琴 —— ST表的更多相关文章
- bzoj 2006 [NOI2010]超级钢琴——ST表+堆
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2006 每个右端点的左端点在一个区间内:用堆记录端点位置.可选区间,按价值排序:拿出一个后也许 ...
- BZOJ 2006: [NOI2010]超级钢琴 [ST表+堆 | 主席树]
题意: 一个序列,求k个不相同的长度属于\([L,R]\)的区间使得和最大 前缀和,对于每个r找最小的a[l] 然后我yy了一个可持久化线段树做法...也许会T 实际上主席树就可以了,区间k小值 然后 ...
- BZOJ 2006: [NOI2010]超级钢琴 ST表+堆
开始想到了一个二分+主席树的 $O(n\log^2 n)$ 的做法. 能过,但是太无脑了. 看了一下题解,有一个 ST 表+堆的优美解法. 你发现肯定是选取前 k 大最优. 然后第一次选的话直接选固定 ...
- 【BZOJ-2006】超级钢琴 ST表 + 堆 (一类经典问题)
2006: [NOI2010]超级钢琴 Time Limit: 20 Sec Memory Limit: 552 MBSubmit: 2473 Solved: 1211[Submit][Statu ...
- [BZOJ2006][NOI2010]超级钢琴(ST表+堆)
2006: [NOI2010]超级钢琴 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3679 Solved: 1828[Submit][Statu ...
- 【BZOJ2006】[NOI2010]超级钢琴 ST表+堆
[BZOJ2006][NOI2010]超级钢琴 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以 ...
- [BZOJ 2006] 超级钢琴
Link: https://www.lydsy.com/JudgeOnline/problem.php?id=2006 Algorithm: 对于此类区间最值类问题,我们可以通过控制一端不变来寻找当前 ...
- BZOJ 2006 超级钢琴(划分树+优先队列)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2006 题意: 给出一个数列A,L,R,构造出一个新的集合,集合中的数字为A中任意连续t( ...
- BZOJ 2006 超级钢琴(堆+主席树)
很好的一道题. 题意:给出长度为n的数列,选择k个互不相同的区间,满足每个区间长度在[L,R]内,求所有选择的区间和的总和最大是多少.(n,k<=5e5). 首先将区间和转化为前缀和之差,那么我 ...
随机推荐
- 【模板】manacher算法
传送门 某篇好文章 #include <cstdio> #include <cstring> #define N 22200000 #define min(x, y) ((x) ...
- [luoguP2216] [HAOI2007]理想的正方形(二维单调队列)
传送门 1.先弄个单调队列求出每一行的区间为n的最大值最小值. 2.然后再搞个单调队列求1所求出的结果的区间为n的最大值最小值 3.最后扫一遍就行 懒得画图,自己体会吧. ——代码 #include ...
- [POJ2594] Treasure Exploration(最小路径覆盖-传递闭包 + 匈牙利算法)
传送门 引子: 有一个问题,是对于一个图上的所有点,用不相交的路径把他们覆盖,使得每个点有且仅属于一条路径,且这个路径数量尽量小. 对于这个问题可以把直接有边相连的两点 x —> y,建一个二分 ...
- 50个必备的实用jQuery代码段(转载)
本文会给你们展示50个jquery代码片段,这些代码能够给你的javascript项目提供帮助.其中的一些代码段是从jQuery1.4.2才开始支持的做法,另一些则是真正有用的函数或方法,他们能够帮助 ...
- 魔咒词典--hdu1880(字符串 暴力)
http://acm.hdu.edu.cn/showproblem.php?pid=1880 不要想其他的 暴力就能过 #include <iostream> #include < ...
- 洛谷—— P1133 教主的花园
https://www.luogu.org/problem/show?pid=1133 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都 ...
- P1003 铺地毯(noip 2011)
洛谷——P1003 铺地毯 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯 ...
- Java学习--反码 原码 补码简析
关于课上实验中对小数的处理中出现的问题涉及到原码,反码,补码的问题,所以在网上进行了一下搜索.在原码,反码,补码中的解释可得知,无论是哪一种码,能够表示的数的范围是-2^(位数-1)+1至2^(位数- ...
- 洛谷 P3807 【模板】卢卡斯定理
P3807 [模板]卢卡斯定理 题目背景 这是一道模板题. 题目描述 给定n,m,p(1\le n,m,p\le 10^51≤n,m,p≤105) 求 C_{n+m}^{m}\ mod\ pCn+mm ...
- Spring Boot中验证码实现kaptcha
要生成验证码网上的方案比较多,基本是基于两大类:1为自定义生成,操作用Image类,2为kaptcha生成,有模糊算法. 当然也可以直接交由前端进行处理 1.基于kaptcha 首先不要怀疑的是报名是 ...