2024.4.5 RMQ补题
P2048 [NOI2010] 超级钢琴
前缀和处理连续子段的和弦,然后 rmq 求最大值
运用堆存储最优答案
每次取出堆头统计一次后,除掉统计点再分成两段加入即可,共 k 次
#include<bits/stdc++.h>
#define maxn 500010
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
int n,k,l,r,ans;
int f[maxn][30],sum[maxn];
struct node{
int fr,to,l,r;
bool operator < (const node &b) const{
return sum[to]-sum[fr-1]<sum[b.to]-sum[b.fr-1];
}
};
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
int query(int l,int r){
int k=log2(r-l+1);
int x=f[l][k],y=f[r-(1<<k)+1][k];
return sum[x]>sum[y]?x:y;
}
signed main(){
// memset(f,128,sizeof f);
n=read();k=read();l=read();r=read();
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+read(),f[i][0]=i;
int lenth=log2(n);
for(int j=1;j<=lenth;j++)
for(int i=1;i+(1<<j)-1<=n;i++){
int x=f[i][j-1],y=f[i+(1<<(j-1))][j-1];
f[i][j]=(sum[x]>sum[y])?x:y;
}
priority_queue<node> q;
for(int i=1;i<=n;i++)
if(i+l-1<=n) q.push((node){i,query(i+l-1,min(n,i+r-1)),i+l-1,min(n,i+r-1)});
for(int i=1;i<=k;i++){
node u=q.top();q.pop();
ans+=sum[u.to]-sum[u.fr-1];
if(u.l!=u.to) q.push((node){u.fr,query(u.l,u.to-1),u.l,u.to-1});
if(u.r!=u.to) q.push((node){u.fr,query(u.to+1,u.r),u.to+1,u.r});
}
printf("%lld\n",ans);
return 0;
}
UVA11235 Frequent values
非降序数列,因此可以直接统计数字的值和个数,即数字段的长度
再记录每一段的左右和每个点所在的段数
查 (l,r) 就可以查中间的若干段和两边的残段,其中中间用 st 表
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
int n,q,le,ri,ans;
int a[maxn],num[maxn],l[maxn],r[maxn],d[maxn][30];
vector<int> cnt;
int query(int l,int r){
int k=log2(r-l+1);
return max(d[l][k],d[r-(1<<k)+1][k]);
}
int main(){
while (scanf("%d",&n)){
if (!n) break;q=read();
for (int i=0;i<n;++i) a[i]=read();
a[n]=a[n-1]+1;int start=-1;
for (int i=1;i<=n;++i){
if (i==0||a[i]>a[i-1]){
if (i>0) {
cnt.push_back(i-start);
for (int j=start; j<i; ++j) {
num[j]=cnt.size()-1;
l[j]=start;r[j]=i-1;
}
}
start=i;
}
}
int _n=cnt.size();
for (int i=0;i<_n;++i) d[i][0]=cnt[i];
for (int j=1;(1<<j)<=_n;++j)
for (int i=0;i+(1<<j)-1<_n;++i)
d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
while (q--){
le=read()-1;ri=read()-1;
if (num[le]==num[ri]) ans=ri-le+1;
else {
ans=max(ri-l[ri]+1,r[le]-le+1);
if(num[le]+1<num[ri])
ans=max(ans, query(num[le]+1,num[ri]-1));
}
printf("%d\n", ans);
}
}
return 0;
}
UVA11297Census
二维 rmq
再一个方向开个线段树,然后每个点为另一个方向开一个新的线段树
#include <bits/stdc++.h>
using namespace std;
int n,m,a[501][501],maxn,minn;
struct node{ int maxv,minv;}p[2001][2001];
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
void build2(int mo,int ml,int mr,int o,int l,int r){
if(l!=r){
int m=(l+r)>>1;
build2(mo,ml,mr,o<<1,l,m);
build2(mo,ml,mr,(o<<1)+1,m+1,r);
p[mo][o].maxv=max(p[mo][o<<1].maxv,p[mo][(o<<1)+1].maxv);
p[mo][o].minv=min(p[mo][o<<1].minv,p[mo][(o<<1)+1].minv);
}
else{
if(ml==mr)p[mo][o].maxv=p[mo][o].minv=a[ml][l];
else {
p[mo][o].maxv=max(p[mo<<1][o].maxv,p[(mo<<1)+1][o].maxv);
p[mo][o].minv=min(p[mo<<1][o].minv,p[(mo<<1)+1][o].minv);
}
}
}
void build1(int o,int l,int r){
if(l!=r){
int m=(l+r)>>1;
build1(o<<1,l,m);
build1((o<<1)+1,m+1,r);
}
build2(o,l,r,1,1,n);
}
void query2(int o,int l,int r,int ql,int qr,int mo){
if(l>=ql && r<=qr){
maxn=max(maxn,p[mo][o].maxv);
minn=min(minn,p[mo][o].minv);
}
else{
int m=(l+r)>>1;
if(ql<=m)query2(o<<1,l,m,ql,qr,mo);
if(qr>m)query2((o<<1)+1,m+1,r,ql,qr,mo);
}
}
void query1(int o,int l,int r,int ql,int qr,int l2,int r2){
if(l>=ql && r<=qr){
query2(1,1,n,l2,r2,o);
}
else{
int m=(l+r)>>1;
if(ql<=m)query1(o<<1,l,m,ql,qr,l2,r2);
if(qr>m)query1((o<<1)+1,m+1,r,ql,qr,l2,r2);
}
}
void update2(int o,int l,int r,int q,int val,int mo){
if(l==r){
if(val==-1){
p[mo][o].maxv=max(p[mo<<1][o].maxv,p[(mo<<1)+1][o].maxv);
p[mo][o].minv=min(p[mo<<1][o].minv,p[(mo<<1)+1][o].minv);
return;
}
p[mo][o].maxv=p[mo][o].minv=val;
return;
}
int m=(l+r)>>1;
if(q<=m)update2(o<<1,l,m,q,val,mo);else update2((o<<1)+1,m+1,r,q,val,mo);
p[mo][o].maxv=max(p[mo][o<<1].maxv,p[mo][(o<<1)+1].maxv);
p[mo][o].minv=min(p[mo][o<<1].minv,p[mo][(o<<1)+1].minv);
}
void update1(int o,int l,int r,int qx,int qy,int val){
if(l==r) update2(1,1,n,qy,val,o);
else {
int m=(l+r)>>1;
if(qx<=m)update1(o<<1,l,m,qx,qy,val);
else update1((o<<1)+1,m+1,r,qx,qy,val);
update2(1,1,n,qy,-1,o);
}
}
int main() {
n=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
a[i][j]=read();
build1(1,1,n);m=read();char opt;
for(int i=1,x,y,c,xx,yy;i<=m;++i){
cin>>opt;
if(opt=='q'){
x=read();y=read();xx=read();yy=read();
minn=0x3f3f3f3f;maxn=0;
query1(1,1,n,x,xx,y,yy);
printf("%d %d\n",maxn,minn);
}
else {
scanf("%d%d%d",&x,&y,&c);
update1(1,1,n,x,y,c);
}
}
}