穿梭时间的画面的钟 从反方向 开始移动|

tmjyh09

园龄:3年2个月粉丝:1关注:3

loj 数列分块入门 1 ~ 9 做题笔记

前言

做了 hzwer 的分块系列(

%%% hzwer 学长

loj6277 数列分块入门 1

给定数列,区间修改,单点查询。

区间修改可以打永久标记。没什么好说的,毕竟是 1。

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f^=!(ch^45),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
inline void write(int x){
if(x<0)x=-x,putchar('-');
if(x>=10)write(x/10);
putchar(x%10+'0');
}
inline void writeln(int x){write(x);puts("");}
int n;
int a[50005];
int block,num;
int L[500005],R[500005];
int pos[500005];
int sum[500005],add[500005];
void build(){
block=sqrt(n);
num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=i*block;
}
R[num]=n;
for(int i=1;i<=num;i++){
for(int j=L[i];j<=R[i];j++){
pos[j]=i;
sum[i]+=a[j];
}
}
}
void update(int l,int r,int k){
int x=pos[l],y=pos[r];
if(x==y){
for(int i=l;i<=r;i++){
a[i]+=k;
}
sum[x]+=k*(r-l+1);
}else{
for(int i=x+1;i<=y-1;i++){
add[i]+=k;
}
for(int i=l;i<=R[x];i++){
a[i]+=k;
sum[x]+=k;
}
for(int i=L[y];i<=r;i++){
a[i]+=k;
sum[y]+=k;
}
}
}
int query(int l,int r){
int x=pos[l],y=pos[r];
int ans=0;
if(x==y){
for(int i=l;i<=r;i++)ans+=a[i];
ans+=add[x]*(r-l+1);
}
else{
for(int i=x+1;i<=y-1;i++){
ans+=sum[i]+add[i]*(R[i]-L[i]+1);
}
for(int i=l;i<=R[x];i++){
ans+=a[i];
}
ans+=add[x]*(R[x]-l+1);
for(int i=L[y];i<=r;i++){
ans+=a[i];
}
ans+=add[y]*(r-L[y]+1);
}
return ans;
}
signed main(){
n=read();
for(int i=1;i<=n;i++)a[i]=read();
build();
while(n--){
int op=read(),l=read(),r=read(),c=read();
if(op==0)update(l,r,c);
else writeln(query(r,r));
}
#ifndef ONLINE_JUDGE
system("pause");
#endif
return 0;
}

loj6278 数列分块入门 2

给定数列,区间加,区间查询小于 x 的个数。

233333333 线段树你做不了了 hhh

区间小于某个数可以二分求解。复制一份辅助数组 d,初值全部等于 a,对每个块内进行排序。

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f^=!(ch^45),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
inline void write(int x){
if(x<0)x=-x,putchar('-');
if(x>=10)write(x/10);
putchar(x%10+'0');
}
inline void writeln(int x){write(x);puts("");}
int n;
int block,num;
int pos[50005];
int sum[50005];
int add[50005];
int L[50005],R[50005];
int a[50005],d[50005];
void build(){
block=sqrt(n);
num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=i*block;
}
R[num]=n;
for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1;
for(int i=1;i<=num;i++){
for(int j=L[i];j<=R[i];j++)sum[i]+=a[j];
sort(d+L[i],d+R[i]+1);
}
}
void update(int l,int r,int k){
int x=pos[l],y=pos[r];
if(x==y){
for(int i=l;i<=r;i++)a[i]+=k;
sum[x]+=(r-l+1)*k;
for(int i=L[x];i<=R[x];i++)d[i]=a[i];
sort(d+L[x],d+R[x]+1);
}else{
for(int i=x+1;i<=y-1;i++)add[i]+=k;
//------------------
for(int i=l;i<=R[x];i++)a[i]+=k;
sum[x]+=(R[x]-l+1)*k;
for(int i=L[x];i<=R[x];i++)d[i]=a[i];
sort(d+L[x],d+R[x]+1);
//------------------
for(int i=L[y];i<=r;i++)a[i]+=k;
sum[y]+=(r-L[y]+1)*k;
for(int i=L[y];i<=R[y];i++)d[i]=a[i];
sort(d+L[y],d+R[y]+1);
}
}
int query(int l,int r,int k){
int ans=0;
int x=pos[l],y=pos[r];
if(x==y){
for(int i=l;i<=r;i++)if(a[i]+add[x]<k)ans++;
}else{
for(int i=l;i<=R[x];i++)if(a[i]+add[x]<k)ans++;
for(int i=L[y];i<=r;i++)if(a[i]+add[y]<k)ans++;
for(int i=x+1;i<=y-1;i++){
ans+=lower_bound(d+L[i],d+R[i]+1,k-add[i])-d-L[i];
}
}
return ans;
}
signed main(){
n=read();
for(int i=1;i<=n;i++)a[i]=d[i]=read();
build();
while(n--){
int op=read(),l=read(),r=read(),c=read();
if(op==0)update(l,r,c);
else writeln(query(l,r,c*c));
}
#ifndef ONLINE_JUDGE
system("pause");
#endif
return 0;
}

loj6279 数列分块入门 3

给定数列,区间加,区间前驱。

loj 的分块题就离不开区间加法

前驱可以二分求解。

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 1e5+10;
int n;
int a[N];
int L[N],R[N],pos[N],add[N],d[N];
int block,num;
void build(){
block=sqrt(n);
num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=i*block;
}
R[num]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
}
for(int i=1;i<=num;i++){
sort(d+L[i],d+R[i]+1);
}
}
void update(int l,int r,int k){
int x=pos[l],y=pos[r];
if(x==y){
for(int i=l;i<=r;i++)a[i]+=k;
for(int i=L[x];i<=R[x];i++)d[i]=a[i];
sort(d+L[x],d+R[x]+1);
return;
}
//左端零散块
for(int i=l;i<=R[x];i++)a[i]+=k;
for(int i=L[x];i<=R[x];i++)d[i]=a[i];
sort(d+L[x],d+R[x]+1);
//中间完整块
for(int i=x+1;i<=y-1;i++)add[i]+=k;
//右端零散块
for(int i=L[y];i<=r;i++)a[i]+=k;
for(int i=L[y];i<=R[y];i++)d[i]=a[i];
sort(d+L[y],d+R[y]+1);
}
int query(int l,int r,int k){
int x=pos[l],y=pos[r];
if(x==y){
int ans=-0x3f3f3f3f;
for(int i=l;i<=r;i++){
if(a[i]+add[x]<k){
ans=max(ans,a[i]+add[x]);
}
}
return ans==-0x3f3f3f3f?-1:ans;
}
int ans=-0x3f3f3f3f;
for(int i=l;i<=R[x];i++){
if(a[i]+add[x]<k){
ans=max(ans,a[i]+add[x]);
}
}
for(int i=L[y];i<=r;i++){
if(a[i]+add[y]<k){
ans=max(ans,a[i]+add[y]);
}
}
//完整块
for(int i=x+1;i<=y-1;i++){
int cur=lower_bound(d+L[i],d+R[i]+1,k-add[i])-d;
if(cur==L[i])continue;
ans=max(ans,d[cur-1]+add[i]);
}
return ans==-0x3f3f3f3f?-1:ans;
}
int main(){
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],d[i]=a[i];
build();
while(n--){
int opt,l,r,c;
cin>>opt>>l>>r>>c;
if(opt==0){
update(l,r,c);
}else{
cout<<query(l,r,c)<<endl;
}
}
return 0;
}

loj6280 数列分块入门 4

数列区间加区间求和。

非常正常的一道线段树分块题。

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f^=!(ch^45),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
inline void write(int x){
if(x<0)x=-x,putchar('-');
if(x>=10)write(x/10);
putchar(x%10+'0');
}
inline void writeln(int x){write(x);puts("");}
int n;
int a[50005];
int block,num;
int L[500005],R[500005];
int pos[500005];
int sum[500005],add[500005];
void build(){
block=sqrt(n);
num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=i*block;
}
R[num]=n;
for(int i=1;i<=num;i++){
for(int j=L[i];j<=R[i];j++){
pos[j]=i;
sum[i]+=a[j];
}
}
}
void update(int l,int r,int k){
int x=pos[l],y=pos[r];
if(x==y){
for(int i=l;i<=r;i++){
a[i]+=k;
}
sum[x]+=k*(r-l+1);
}else{
for(int i=x+1;i<=y-1;i++){
add[i]+=k;
}
for(int i=l;i<=R[x];i++){
a[i]+=k;
sum[x]+=k;
}
for(int i=L[y];i<=r;i++){
a[i]+=k;
sum[y]+=k;
}
}
}
int query(int l,int r){
int x=pos[l],y=pos[r];
int ans=0;
if(x==y){
for(int i=l;i<=r;i++)ans+=a[i];
ans+=add[x]*(r-l+1);
}
else{
for(int i=x+1;i<=y-1;i++){
ans+=sum[i]+add[i]*(R[i]-L[i]+1);
}
for(int i=l;i<=R[x];i++){
ans+=a[i];
}
ans+=add[x]*(R[x]-l+1);
for(int i=L[y];i<=r;i++){
ans+=a[i];
}
ans+=add[y]*(r-L[y]+1);
}
return ans;
}
signed main(){
n=read();
for(int i=1;i<=n;i++)a[i]=read();
build();
while(n--){
int op=read(),l=read(),r=read(),c=read();
if(op==0)update(l,r,c);
else writeln(query(l,r)%(c+1));
}
#ifndef ONLINE_JUDGE
system("pause");
#endif
return 0;
}

loj6281 数列分块入门 5

给定数列,区间开方,区间求和。

i[1,n],ai[0,2311],在这个范围内,ai 最多开根 67 次就会变为 1,此时再开根是无意义的,所以维护 tagi 表示第 i 块是否都变为 10(反正再开根无意义的数),若 tagi=0 暴力操作整块。

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 5e4 + 10;
int n;
int a[N];
int pos[N],L[N],R[N],sum[N],tag[N];
int block,num;
void build(){
block=sqrt(n);
num=n/block;if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=i*block;
}
R[num]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
sum[pos[i]]+=a[i];
}
}
void Sqrt(int x){
if(tag[x])return;
sum[x]=0;tag[x]=1;
for(int i=L[x];i<=R[x];i++){
a[i]=sqrt(a[i]);
sum[x]+=a[i];
if(a[i]>1)tag[x]=0;
}
}
void update(int l,int r){
int x=pos[l],y=pos[r];
if(x==y){
for(int i=l;i<=r;i++){
sum[x]-=a[i];
a[i]=sqrt(a[i]);
sum[x]+=a[i];
}
return;
}
for(int i=l;i<=R[x];i++){
sum[x]-=a[i];
a[i]=sqrt(a[i]);
sum[x]+=a[i];
}
for(int i=x+1;i<=y-1;i++)Sqrt(i);
for(int i=L[y];i<=r;i++){
sum[y]-=a[i];
a[i]=sqrt(a[i]);
sum[y]+=a[i];
}
}
int query(int l,int r){
int x=pos[l],y=pos[r];
if(x==y){
int ans=0;
for(int i=l;i<=r;i++)ans+=a[i];
return ans;
}
int ans=0;
for(int i=l;i<=R[x];i++)ans+=a[i];
for(int i=x+1;i<=y-1;i++)ans+=sum[i];
for(int i=L[y];i<=r;i++)ans+=a[i];
return ans;
}
int main(){
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
build();
while(n--){
int opt,l,r,c;
cin>>opt>>l>>r>>c;
if(opt==0){
update(l,r);
}else{
cout<<query(l,r)<<endl;
}
}
return 0;
}

loj6282 数列分块入门 6

数列单点插入单点查询。

恕本人蒟蒻,实在想不出这题如何用分块解答。

看到插入果断选择 splay。

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 2e5+10;
int n,root;
struct node{
int son[2],fa,val,siz;
}tr[N];
#define ls(x) (tr[x].son[0])
#define rs(x) (tr[x].son[1])
#define fa(x) (tr[x].fa)
inline void pushup(int x){tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;}
void rotate(int x){
int y=fa(x),z=fa(y);
int k=rs(y)==x;
tr[z].son[rs(z)==y]=x,fa(x)=z;
tr[y].son[k]=tr[x].son[k^1],fa(tr[x].son[k^1])=y;
tr[x].son[k^1]=y,fa(y)=x;
pushup(y);pushup(x);
}
void splay(int x,int goal){
while(fa(x)!=goal){
int y=fa(x),z=fa(y);
if(z!=goal){
if((rs(z)==y) ^ (rs(y)==x))rotate(x);
else rotate(y);
}
rotate(x);
}
if(!goal)root=x;
}
int kth(int k){
int x=root;
while(true){
if(tr[ls(x)].siz>=k)x=ls(x);
else if(tr[ls(x)].siz+1>=k)return x;
else k-=tr[ls(x)].siz+1,x=rs(x);
}
}
int a[N];
int idx;
int New(int val,int fa){
tr[++idx].fa=fa;tr[idx].siz=1;tr[idx].val=val;return idx;
}
void build(int &p,int l,int r,int fa){
if(l>r)return;
int mid=l+r>>1;
p=New(a[mid],fa);
build(ls(p),l,mid-1,p);
build(rs(p),mid+1,r,p);
pushup(p);
}
void init(){
root=New(-0x3f3f3f3f,0);
rs(root)=New(0x3f3f3f3f,root);
tr[root].siz=2;
build(ls(rs(root)),1,n,rs(root));
pushup(rs(root));pushup(root);
}
void insert(int pos,int val){
int x=kth(pos-1),y=kth(pos);
splay(x,0);splay(y,x);
ls(y)=New(val,y);
pushup(y);pushup(x);
}
int main(){
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
init();
while(n--){
int p,l,r,c;
cin>>p>>l>>r>>c;
if(p==0){
++l;
insert(l,r);
}else{
++r;
splay(kth(r),0);
cout<<tr[root].val<<endl;
}
}
return 0;
}

loj6283 数列分块入门 7

给定数列,区间乘,区间加,单点查询。

维护两个懒标记,但是这里情况比较特殊,并不是使用永久标记,而是会类似线段树那样下传标记,注意先乘后加,然后正常维护即可。

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define mod 10007
using namespace std;
const int N = 1e5+10;
int n;
int a[N];
int pos[N],L[N],R[N],add[N],mul[N];
int block,num;
void build(){
block=sqrt(n);
num=n/block;
if(n%block)num++;
for(int i=1;i<=num;i++){
mul[i]=1;
L[i]=(i-1)*block+1;
R[i]=i*block;
}
R[num]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
}
}
void clear(int x){
for(int i=L[x];i<=R[x];i++){
a[i]=a[i]*mul[x]%mod;
a[i]=(a[i]+add[x])%mod;
}
mul[x]=1;add[x]=0;
}
void Mul(int l,int r,int k){
int x=pos[l],y=pos[r];
if(x==y){
clear(x);
for(int i=l;i<=r;i++){
a[i]=a[i]*k%mod;
}
return;
}
clear(x);
for(int i=l;i<=R[x];i++){
a[i]=a[i]*k%mod;
}
clear(y);
for(int i=L[y];i<=r;i++){
a[i]=a[i]*k%mod;
}
for(int i=x+1;i<y;i++){
add[i]=add[i]*k%mod;mul[i]=mul[i]*k%mod;
}
}
void Add(int l,int r,int k){
int x=pos[l],y=pos[r];
if(x==y){
clear(x);
for(int i=l;i<=r;i++){
a[i]=(a[i]+k)%mod;
}
return;
}
clear(x);
for(int i=l;i<=R[x];i++){
a[i]=(a[i]+k)%mod;
}
for(int i=x+1;i<y;i++){
add[i]=(add[i]+k)%mod;
}
clear(y);
for(int i=L[y];i<=r;i++){
a[i]=(a[i]+k)%mod;
}
}
signed main(){
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
build();
while(n--){
int opt,l,r,c;
cin>>opt>>l>>r>>c;
if(opt==0)Add(l,r,c);
if(opt==1)Mul(l,r,c);
if(opt==2)cout<<(a[r]*mul[pos[r]]%mod+add[pos[r]])%mod<<endl;
}
return 0;
}

loj6284 数列分块入门 8

给定数列,求区间 =c 个数并覆盖为 c

同样采用下放标记的方式。

在查询,如果发现第 i 已经覆盖成 c,就把整块加上去,如果没有打过标记就暴力统计。

#include <bits/stdc++.h>
#define endl '\n'
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1e5 + 10;
int a[N],n;
int L[N],R[N],pos[N];
int cov[N];
int block,num;
void build(){
block=sqrt(n);
num=n/block;if(n%block)num++;
for(int i=1;i<=num;i++){
L[i]=(i-1)*block+1;
R[i]=i*block;
cov[i]=inf;
}
R[num]=n;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
}
}
void clear(int x){
if(cov[x]==inf)return;
for(int i=L[x];i<=R[x];i++){
a[i]=cov[x];
}
cov[x]=inf;
}
int query(int l,int r,int c){
int x=pos[l],y=pos[r];
int ans=0;
if(x==y){
clear(x);
for(int i=l;i<=r;i++){
ans+=a[i]==c;a[i]=c;
}
return ans;
}
clear(x);
for(int i=l;i<=R[x];i++){
ans+=a[i]==c;a[i]=c;
}
clear(y);
for(int i=L[y];i<=r;i++){
ans+=a[i]==c;a[i]=c;
}
for(int i=x+1;i<y;i++){
if(cov[i]==c)ans+=R[i]-L[i]+1;
if(cov[i]==inf){
for(int j=L[i];j<=R[i];j++){
ans+=a[j]==c;
}
}
cov[i]=c;
}
return ans;
}
int main(){
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
build();
while(n--){
int l,r,c;
cin>>l>>r>>c;
cout<<query(l,r,c)<<endl;
}
return 0;
}

loj6285 数列分块入门 9*

Boss 来了。

给定数列,求区间最小众数。

回忆一下我们平时是怎么算众数的,我们开桶 t 记录每个数出现的次数,最后扫一遍 t 即可。

分块预处理

看一下题目的数据范围:231others2311(也就是 int 的范围),这么大,用数组会炸掉,而如果用 std::map,会给复杂度再加上 log,显然不优(更多详细原因阅读脚注),所以需要离散化,这里使用 unique + lower_bound 的离散化方法。

这样得到的 a 数组是原 b 数组中对应的数的下标,输出时须留意。

离散化过后,我们就可以预处理出前缀和数组 si,j 表示前 i 块中 j 出现的次数。

对于两端零散的块,我们暴力统计;对于中间完整的块,就需要预处理了。

我们预处理出 fi,j 表示第 i 块到第 j 块的众数。

区间查询众数

看一张图来理解:

此时数列已经分成 n (n=10) 块,已用不同颜色标出。

我们查找 l=2,r=7,显然我们早已求出 f,现在就是要处理两端绿色部分(零散部分),两端的部分出现次数怎么算呢?先用一个桶统计,然后还得加上中间块(橙色部分)的出现次数,用 s 前缀和可以得到。

一点优化

注:此处设 posi 为第 i 个数属于第几块。

可以发现,当 |posrposl|1 时,对于中间块的操作,使用 f 数组查询跟我们暴力处理没有区别,s 数组统计中间块的出现次数,因为只有 1 块,所以优化效果微乎其微。

所以当 |posrposl|1 我们就打暴力,否则就分块处理。

说句闲话

表示每块起始的数组名从 L,R 改成了 st,ed,因为觉得按 Shift 麻烦。

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N],b[N];
int st[N],ed[N],pos[N];
int f[318][318];
int s[318][N];
int block,num;
int m[N];
int main(){
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)cin>>b[i],a[i]=b[i];
sort(b+1,b+n+1);
int len=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+len+1,a[i])-b;
}
block=sqrt(n);num=n/block;if(n%block)num++;
for(int i=1;i<=num;i++){
st[i]=(i-1)*block+1;
ed[i]=i*block;
}
for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1;
for(int i=1;i<=num;i++){
for(int j=st[i];j<=ed[i];j++)s[i][a[j]]++;
for(int j=1;j<=len;j++)s[i][j]+=s[i-1][j];
}
for(int i=1;i<=num;i++){
for(int j=i;j<=num;j++){
int mx=f[i][j-1];
for(int k=st[j];k<=ed[j];k++){
if(s[j][a[k]]-s[i-1][a[k]]>=s[j][mx]-s[i-1][mx]){
if(s[j][a[k]]-s[i-1][a[k]]==s[j][mx]-s[i-1][mx]){
mx=min(mx,a[k]);
}
else mx=a[k];
}
}
f[i][j]=mx;
}
}
while(n--){
int l,r;cin>>l>>r;
int x=pos[l],y=pos[r];
int ans=0;
if(y-x<=1){
for(int i=l;i<=r;i++){
m[a[i]]++;
if(m[a[i]]>=m[ans]){
if(m[a[i]]==m[ans])ans=min(ans,a[i]);
else ans=a[i];
}
}
for(int i=l;i<=r;i++)m[a[i]]=0;
}else{
ans=f[x+1][y-1];
for(int i=l;i<=ed[x];i++)m[a[i]]++;
for(int i=st[y];i<=r;i++)m[a[i]]++;
for(int i=l;i<=ed[x];i++){
if(m[a[i]]+s[y-1][a[i]]-s[x][a[i]]>=m[ans]+s[y-1][ans]-s[x][ans]){
if(m[a[i]]+s[y-1][a[i]]-s[x][a[i]]==m[ans]+s[y-1][ans]-s[x][ans])ans=min(ans,a[i]);
else ans=a[i];
}
}
for(int i=st[y];i<=r;i++){
if(m[a[i]]+s[y-1][a[i]]-s[x][a[i]]>=m[ans]+s[y-1][ans]-s[x][ans]){
if(m[a[i]]+s[y-1][a[i]]-s[x][a[i]]==m[ans]+s[y-1][ans]-s[x][ans])ans=min(ans,a[i]);
else ans=a[i];
}
}
for(int i=l;i<=ed[x];i++)m[a[i]]=0;
for(int i=st[y];i<=r;i++)m[a[i]]=0;
}
cout<<b[ans]<<endl;
}
return 0;
}

  1. 其实用 std::map 当桶处理大数据也可以,带个 log 其实也不会超时,麻烦就麻烦在数组 s 的处理上,因为按照值域来更新,不离散化值域过大,这里才是超时的原因,所以 std::map 寄了。 ↩︎

本文作者:tmjyh09

本文链接:https://www.cnblogs.com/tmjyh09/p/16192081.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   tmjyh09  阅读(51)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起