分块
P2801 教主的魔法
分块即可,复制一个数组保持块内有序,然后用一个数组记录块整体的加减情况,就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
int n,x,m,q;
int a[N],b[N];
struct node{
int st,ed,tag;
}k[N];
void change(int l,int r,int w){
int lx=(l-1)/x+1,rx=(r-1)/x+1;
if(lx==rx){
for(int i=l;i<=r;i++) a[i]+=w;
for(int i=k[lx].st;i<=k[lx].ed;i++) b[i]=a[i];
sort(b+k[lx].st,b+k[lx].ed+1);
return;
}
for(int i=l;i<=k[lx].ed;i++) a[i]+=w;
for(int i=k[lx].st;i<=k[lx].ed;i++) b[i]=a[i];
sort(b+k[lx].st,b+k[lx].ed+1);
for(int i=k[rx].st;i<=r;i++) a[i]+=w;
for(int i=k[rx].st;i<=k[rx].ed;i++) b[i]=a[i];
sort(b+k[rx].st,b+k[rx].ed+1);
for(int i=lx+1;i<rx;i++) k[i].tag+=w;
}
int query(int l,int r,int c){
int res=0;
int lx=(l-1)/x+1,rx=(r-1)/x+1;
if(lx==rx){
for(int i=l;i<=r;i++) if(a[i]+k[lx].tag>=c) res++;
return res;
}
for(int i=l;i<=k[lx].ed;i++) if(a[i]+k[lx].tag>=c) res++;
for(int i=k[rx].st;i<=r;i++) if(a[i]+k[rx].tag>=c) res++;
for(int i=lx+1;i<rx;i++){
int id=lower_bound(b+k[i].st,b+k[i].ed+1,c-k[i].tag)-b;
if(id>=k[i].st&&id<=k[i].ed) res+=k[i].ed-id+1;
}
return res;
}
signed main(){
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>a[i],b[i]=a[i];
x=sqrt(1.0*n);
m=ceil(1.0*n/(1.0*x));
for(int i=1;i<=m;i++){
k[i].st=(i-1)*x+1,k[i].ed=min(i*x,n);
sort(b+k[i].st,b+k[i].ed+1);
}
while(q--){
char op;
int l,r,w;
cin>>op>>l>>r>>w;
if(op=='M') change(l,r,w);
else cout<<query(l,r,w)<<"\n";
}
return 0;
}P4168 [Violet] 蒲公英
预处理一下每两个块之间的众数以及前几个块每个值的个数,
先算出中间块的众数加上两边相等的数量,在看两边散块的值加上中间的值是否比当前答案大,都可以用预处理来的数据计算。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e5+5;
const int M=sqrt(N)+3;
int n,x,m,q,ans;
int a[N],b[N];
int cnt[N],f[M][N],g[M][M];
struct node{int st,ed;} k[N];
void init(){
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++) f[i][j]=f[i-1][j];
for(int j=k[i].st;j<=k[i].ed;j++) f[i][a[j]]++;
}
for(int i=1;i<=m;i++){
memset(cnt,0,sizeof cnt);
int res=0,sum=0;
for(int i2=i;i2<=m;i2++){
for(int j=k[i2].st;j<=k[i2].ed;j++){
cnt[a[j]]++;
if(cnt[a[j]]>sum||(cnt[a[j]]==sum&&a[j]<res)) res=a[j],sum=cnt[a[j]];
}
g[i][i2]=res;
}
}
memset(cnt,0,sizeof cnt);
}
int query(int l,int r){
int lx=(l-1)/x+1,rx=(r-1)/x+1;
if(rx-lx<=1){
int res=0;
for(int i=l;i<=r;i++) cnt[a[i]]=0;
for(int i=l;i<=r;i++){
cnt[a[i]]++;
if(cnt[a[i]]>cnt[res]||(cnt[a[i]]==cnt[res]&&a[i]<res)) res=a[i];
}
return res;
}
int res=g[lx+1][rx-1];
int sum=f[rx-1][res]-f[lx][res];
for(int i=l;i<=k[lx].ed;i++) sum+=(a[i]==res),cnt[a[i]]=0;
for(int i=k[rx].st;i<=r;i++) sum+=(a[i]==res),cnt[a[i]]=0;
for(int i=l;i<=k[lx].ed;i++) cnt[a[i]]++;
for(int i=k[rx].st;i<=r;i++) cnt[a[i]]++;
for(int i=l;i<=k[lx].ed;i++){
int tot=f[rx-1][a[i]]-f[lx][a[i]]+cnt[a[i]];
if(tot>sum||(tot==sum&&a[i]<res)) sum=tot,res=a[i];
}
for(int i=k[rx].st;i<=r;i++){
int tot=f[rx-1][a[i]]-f[lx][a[i]]+cnt[a[i]];
if(tot>sum||(tot==sum&&a[i]<res)) sum=tot,res=a[i];
}
return res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>b[i],a[i]=b[i];
sort(b+1,b+1+n);
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+n,a[i])-b;
x=sqrt(1.0*n);
m=(n+x-1)/x;
for(int i=1;i<=m;i++) k[i].st=(i-1)*x+1,k[i].ed=min(i*x,n);
init();
for(int i=1;i<=n;i++){
int l,r;
cin>>l>>r;
ans=b[query(l,r)];
cout<<ans<<"\n";
}
return 0;
}P5048 [Ynoi2019 模拟赛] Yuno loves sqrt technology III
用一个数组表示每两个块之间众数的个数,一个 vector 表示每个值在原数组的下标,一个数组表示当前数在 vector 的下标。
答案先暂定为中间块的众数,然后再扫两边的散块,vector 往前或往后一个一个扫下标,直到超出左右两边的边界。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+5,M=720;
int n,x,m,q,ans;
int a[N],b[N];
int in[N],st[M],ed[M];
int f[M][M],pos[N],cnt[N];
vector<int> p[N];
void init(){
x=sqrt(1.0*n),m=(n+x-1)/x;
sort(b+1,b+1+n);
for(int i=1;i<=n;i++){
in[i]=(i-1)/x+1;
a[i]=lower_bound(b+1,b+1+n,a[i])-b;
p[a[i]].push_back(i);
pos[i]=p[a[i]].size()-1;
}
for(int i=1;i<=m;i++) st[i]=(i-1)*x+1,ed[i]=min(i*x,n);
for(int i=1;i<=m;i++){
memset(cnt,0,sizeof cnt);
for(int j=i;j<=m;j++){
f[i][j]=f[i][j-1];
for(int k=st[j];k<=ed[j];k++) f[i][j]=max(f[i][j],++cnt[a[k]]);
}
}
}
int query(int l,int r){
if(l>r||l>n) return 0;
l=max(1ll,l),r=min(n,r);
int ans=-1;
if(in[l]==in[r]){
for(int i=l;i<=r;i++) cnt[a[i]]=0;
for(int i=l;i<=r;i++) ans=max(ans,++cnt[a[i]]);
return ans;
}
ans=f[in[l]+1][in[r]-1];
for(int i=l;i<=ed[in[l]];i++) while(pos[i]+ans<p[a[i]].size()&&p[a[i]][pos[i]+ans]<=r) ans++;
for(int i=r;i>=st[in[r]];i--) while(pos[i]-ans>=0&&p[a[i]][pos[i]-ans]>=l) ans++;
return ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>b[i],a[i]=b[i];
init();
while(q--){
int l,r;
cin>>l>>r;
l^=ans,r^=ans;
ans=query(l,r);
cout<<ans<<"\n";
}
return 0;
}

Comments NOTHING