【学习笔记】四毛子算法/ The Method of Four Russians
The Method of Four Russians
有些分块问题块间信息合并非常耗时,这算法主要是用 \(\rm{ST}\) 表或者线段树来优化这个过程
例题
upd on 2021-09-19
\(\rm{O(n)-O(1)\ RMQ}\)
本质上是差分序列只有 \(\pm 1\) 的序列的 \(\rm{RMQ}\) 问题
对序列建出 笛卡尔 树后则问题转化为一个 \(LCA\) 问题
使用欧拉序 \(\rm{+ST}\) 表来处理本问题
因为在欧拉序中,相邻的点深度差为 \(\pm 1\),那么设一个块的大小为 \(b=\frac{\log_2 n}2\)
那么一个段的 \(\pm 1\) 一共有 \(2^b\),预处理需要扫描整个段,复杂度 \(\Theta(b2^b)\)
对于段之间的,使用四毛子算法的思想,用 \(\rm{ST}\) 表快速合并,预处理复杂度 \(\Theta(\frac nb \log \frac nb)\)
这两部分均小于 \(\Theta(n)\)
对于小段的处理需要先把块的 \(\pm 1\) 表示左移取 \(\rm{and}\) 之后再计算
LOJ6499颜色
分块,然后用 \(\rm{bitset}\) 处理每个块内出现的颜色种类
因为颜色数量非常大,\(\rm{bitset}\) 做一次 或 操作非常耗费时间
那么可以考虑用 \(\rm{ST}\) 表或者线段树优化这个过程,也就是把块中间的信息先合并上
#include<bits/stdc++.h>
using namespace std;
#define reg register
#define int long long
#define rep(i,a,b) for(reg int i=a;i<=b;++i)
const int N=1e5+10,P=(N>>5)+10,SZ=(1<<16)+1;
int b[N],c,a[N],n,T,p,bl[N],block,ct[SZ];
struct BITSET{
unsigned int a[P];
BITSET operator |(BITSET tp) const{BITSET res; rep(i,0,c) res.a[i]=a[i]|tp.a[i];return res;}
inline void clear(){rep(i,0,c) a[i]=0; return ;}
inline void set(int x){a[x>>5]|=1u<<(x&31); return ;}
inline int count(){int res=0; rep(i,0,c) res+=ct[a[i]>>16]+ct[a[i]&65535]; return res;}
}ans,f[80][9];
inline void work(int l,int r){
if(bl[l]+1>=bl[r]) rep(i,l,r) ans.set(a[i]);
else{
for(reg int i=l;bl[i]==bl[l];++i) ans.set(a[i]);
for(reg int i=r;bl[i]==bl[r];--i) ans.set(a[i]);
int t=log2(bl[r]-bl[l]-1);
ans=ans|f[bl[l]+1][t]|f[bl[r]-(1<<t)][t];
} return ;
}
int lans,k,l,r;
signed main(){
n=read(); T=read(); p=read(); block=sqrt(1.2*log2(n+1)*n);
for(reg int i=1;i<=65535;++i) ct[i]=ct[i>>1]+(i&1);
rep(i,1,n) bl[i]=i/block+1,b[i]=a[i]=read();
sort(b+1,b+n+1); c=unique(b+1,b+n+1)-b-1;
rep(i,1,n) f[bl[i]][0].set(a[i]=lower_bound(b+1,b+c+1,a[i])-b;);
c>>=5;
for(reg int j=1;(1<<j)<=bl[n];++j){
for(reg int i=1;i+(1<<j)-1<=bl[n];++i){
f[i][j]=f[i][j-1]|f[i+(1<<(j-1))][j-1];
}
}
bool fl=0;
while(T--){
ans.clear(); k=read();
while(k--){
int l=read(),r=read();
if(p&&fl) l=(l^lans)%n+1,r=(r^lans)%n+1;
if(r<l) swap(l,r);
work(l,r);
}fl=1;
printf("%d\n",lans=ans.count());
} return 0;
}
不过这代码里面块的大小是嫖的……
牛客练习赛72F
答案容斥完了就是所有颜色减去 \(dfn\) 序不在那个区间里面的情况
所以冲一个四毛子上去即可
但是卡空间,那么把询问分成 \(10\) 组再做就行了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了