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). 首先将区间和转化为前缀和之差,那么我 ...
随机推荐
- CF651B-Beautiful Paintings
B. Beautiful Paintings time limit per test 1 second memory limit per test 256 megabytes input standa ...
- mac上storm standalone安装
一.安装storm 下载storm http://storm.apache.org/downloads.html export STORM_HOME=/Users/huangjiahong/Docum ...
- BZOJ3926 (后缀自动机)
BZOJ3926 诸神眷顾的幻想乡 Problem : 给一个n个节点的树(n<=10^5), 每个点有一种颜色(c<=10), 询问所有点对之间路径组成字符串的种类.保证叶子节点小于等于 ...
- python学习之-- shelve模块
shelve模块定义:是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle(因为封装了pickle)可支持的python数据格式.功能:可以实现pickle的多次dump和多次 ...
- Baby Step Giant Step model
******************************************** */ #include <stdio.h> #include <string.h> # ...
- 收集的一些Redis操作技巧教程
redis(1).redis入门 redis(2).redis数据类型 redis(3).基于jedis.spring-data-redis 连接操作redis redis(4).基于redis 构建 ...
- Java的条件判断
以下内容引用自http://wiki.jikexueyuan.com/project/java/decision-making.html: 在 Java中有两种类型的条件判断语句,它们分别是: if语 ...
- python读取大文件的方法
python计算文件的行数和读取某一行内容的实现方法 :最简单的办法是把文件读入一个大的列表中,然后统计列表的长度.如果文件的路径是以参数的形式filepath传递的,那么只用一行代码就可以完成我们的 ...
- 解决安装oracle11g r2时提示pdksh conflicts with ksh-20100621-2.el6.i686问题
http://blog.csdn.net/linghao00/article/details/7943740 http://www.2cto.com/os/201306/218566.html 在Ce ...
- 将oracle10g 升级至10.2.0.4
http://blog.csdn.net/launch_225/article/details/7221489 一.单实例环境,全时长一个半钟多. 详细图文说明到这下载 1.停止所有oracle相关进 ...