前一篇:https://www.cnblogs.com/TetrisCandy/p/13775757.html
CF220B Little Elephant and Array
简单到不能再简单的莫队模板题
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=1e6+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
int n,Q,a[N],ans[N];
struct query {int l,r,id;} q[N];
int b[N],cnt[N],tot;
bool cmp(const query &x, const query &y) {
return b[x.l]==b[y.l] ? ((b[x.l]&1) ? x.r<y.r : x.r>y.r) : b[x.l]<b[y.l];
}
void dec(int x) {
if(a[x]>n) return;
if(cnt[a[x]]==a[x]) tot--;
cnt[a[x]]--;
if(cnt[a[x]]==a[x]) tot++;
}
void inc(int x) {
if(a[x]>n) return;
if(cnt[a[x]]==a[x]) tot--;
cnt[a[x]]++;
if(cnt[a[x]]==a[x]) tot++;
}
void solve() {
int bs=pow(n,0.5);
rep(i,1,n) b[i]=(i-1)/bs+1;
sort(q+1,q+Q+1,cmp);
int l=1,r=0;
rep(i,1,Q) {
while(l>q[i].l) inc(--l);
while(r<q[i].r) inc(++r);
while(l<q[i].l) dec(l++);
while(r>q[i].r) dec(r--);
ans[q[i].id]=tot;
}
rep(i,1,Q) printf("%d
",ans[i]);
}
int main() {
n=read(), Q=read();
rep(i,1,n) a[i]=read();
rep(i,1,Q) q[i].l=read(), q[i].r=read(), q[i].id=i;
solve();
return 0;
}
CF617E XOR and Favorite Number
区间异或和转化为两个前缀异或和的异或,于是我们只需要统计一个cnt数组即可。
#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=2e6+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
int n,m,k,s[N],bs,b[N],cnt[N],tot,ans[N];
struct query {int id,l,r;} q[N];
bool cmp(const query &x,const query &y) {
return b[x.l]==b[y.l]?x.r<y.r:x.l<y.l;
}
void inc(int x) {tot+=cnt[s[x]^k], cnt[s[x]]++;}
void dec(int x) {cnt[s[x]]--, tot-=cnt[s[x]^k];}
signed main() {
n=read(), m=read(), k=read(), bs=pow(n,0.5);
rep(i,1,n) s[i]=s[i-1]^read(), b[i]=(i-1)/bs+1;
rep(i,1,m) {
int l=read(), r=read();
q[i]=(query){i,l-1,r};
}
sort(q+1,q+m+1,cmp);
int l=1,r=0;
rep(i,1,m) {
while(l>q[i].l) inc(--l);
while(r<q[i].r) inc(++r);
while(l<q[i].l) dec(l++);
while(r>q[i].r) dec(r--);
ans[q[i].id]=tot;
}
rep(i,1,m) printf("%lld
",ans[i]);
return 0;
}
P3709 大爷的字符串题
一道简单的lxl题。首先转化一下。对于题目所求最多还剩多少rp,我们可以贪心先从小到大撸一遍,然后清空一下,然后再撸一遍。所以答案为区间众数出现次数。
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=2e5+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
int n,m,a[N],bs,b[N],cnt[N],tot[N],tans,ans[N];
struct disc {int id,val;} d[N];
bool cmp(const disc &x,const disc &y) {return x.val<y.val;}
void discrete() {
rep(i,1,n) d[i]=(disc) {i,a[i]};
sort(d+1,d+n+1,cmp);
int cnt=0;
rep(i,1,n) a[d[i].id]=(d[i].val==d[i-1].val?cnt:++cnt);;
}
struct query {int id,l,r;} q[N];
bool cmp2(const query &x,const query &y) {
return b[x.l]==b[y.l]?((b[x.l]&1)?x.r<y.r:x.r>y.r):b[x.l]<b[y.l];
}
void inc(int x) {
tot[cnt[a[x]]]--, tot[++cnt[a[x]]]++;
if(cnt[a[x]]>tans) tans=cnt[a[x]];
}
void dec(int x) {
if(cnt[a[x]]==tans&&tot[cnt[a[x]]]==1) tans=cnt[a[x]]-1;
tot[cnt[a[x]]]--, tot[--cnt[a[x]]]++;
}
int main() {
n=read(), m=read(), bs=pow(n,0.5);
rep(i,1,n) a[i]=read(), b[i]=(i-1)/bs+1;
discrete();
rep(i,1,m) {
int l=read(), r=read();
q[i]=(query){i,l,r};
}
sort(q+1,q+m+1,cmp2);
int l=1,r=0;
rep(i,1,m) {
while(l>q[i].l) inc(--l);
while(r<q[i].r) inc(++r);
while(l<q[i].l) dec(l++);
while(r>q[i].r) dec(r--);
ans[q[i].id]=-tans;
}
rep(i,1,m) printf("%d
",ans[i]);
return 0;
}
莫队上树
把树转化为序列玩莫队。
SP10707 COT2 - Count on a tree II
转化为欧拉序。设第一次出现为 (s_u)。则欧拉序的 ([t_u,s_v]) 中 (u,v) 路径包含的一次,其他一些点包含了两次。两次的我们考虑抵消掉。如果 u v 不是直系路径,那么我们发现其 lca 不在路径上。那怎么办?我们直接加上 LCA 的贡献即可。通过实现把 LCA 一把算好可以做到 (O(nsqrt n))。
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=1e5+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
struct edge {int to,nxt;} e[N*2]; int hd[N],tot;
void add(int u,int v) {e[++tot]=(edge){v,hd[u]};hd[u]=tot;}
int n,m,a[N],f[N][29],d[N],s[N],t[N],et[N],tick,b[N],cnt[N],mt,ans[N];
bool used[N];
struct query{int id,l,r,lca;}q[N];
bool cmp(const query &x, const query &y) {
return b[x.l]==b[y.l] ? ((b[x.l]&1) ? x.r<y.r : x.r>y.r) : b[x.l]<b[y.l];
}
void inc(int x) {mt+=(++cnt[a[et[x]]]==1);}
void dec(int x) {mt-=(--cnt[a[et[x]]]==0);}
void c(int x) {(used[et[x]]^=1)?inc(x):dec(x);}
void dfs(int u,int fa) {
d[u]=d[fa]+1, f[u][0]=fa, et[s[u]=++tick]=u;
rep(h,1,20) f[u][h]=f[f[u][h-1]][h-1];
for(int i=hd[u],v;i;i=e[i].nxt) {
if((v=e[i].to)==fa) continue;
dfs(v,u);
}
et[t[u]=++tick]=u;
}
int lca(int u,int v) {
if(d[u]<d[v]) swap(u,v);
per(h,20,0) if(d[f[u][h]]>=d[v]) u=f[u][h];
if(u==v) return u;
per(h,20,0) if(f[u][h]!=f[v][h]) u=f[u][h],v=f[v][h];
return f[u][0];
}
struct disc{int id,val;}ds[N];
bool cmp2(const disc &x,const disc &y) {return x.val<y.val;}
void discrete() {
rep(i,1,n) ds[i]=(disc){i,a[i]};
sort(ds+1,ds+n+1,cmp2);
int cn=0;
rep(i,1,n) {
if(ds[i].val!=ds[i-1].val) cn++;
a[ds[i].id]=cn;
}
}
signed main() {
n=read(), m=read();
rep(i,1,n) a[i]=read();
discrete();
int bs=pow(n,0.5);
rep(i,1,2*n) b[i]=(i-1)/bs+1;
rep(i,1,n-1) {
int u=read(), v=read();
add(u,v), add(v,u);
}
dfs(1,0);
rep(i,1,m) {
int u=read(), v=read(), l=lca(u,v);
if(s[u]>s[v]) swap(u,v);
if(l==u) q[i]=(query){i,s[u],s[v],0};
else q[i]=(query){i,t[u],s[v],l};
}
sort(q+1,q+m+1,cmp);
int l=1,r=0;
rep(i,1,m) {
while(l>q[i].l) c(--l);
while(r<q[i].r) c(++r);
while(l<q[i].l) c(l++);
while(r>q[i].r) c(r--);
if(q[i].lca) c(s[q[i].lca]);
ans[q[i].id]=mt;
if(q[i].lca) c(s[q[i].lca]);
}
rep(i,1,m) printf("%d
",ans[i]);
return 0;
}
CF375D Tree and Queries
甚至更加简单。由于是子树问询,所以在dfs序上是一个连续完整的区间 ([s_u,t_u])。
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=2e5+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
struct edge {int to,nxt;} e[N*2]; int hd[N],tot;
void add(int u,int v) {e[++tot]=(edge){v,hd[u]};hd[u]=tot;}
int n,c[N],m,bl,b[N],et[N],tick,s[N],t[N],cnt[N],sum[N],ans[N];
struct query{int id,l,r,k;}q[N];
bool cmp(const query &x,const query &y) {
return b[x.l]==b[y.l]?x.r<y.r:b[x.l]<b[y.l];
}
void inc(int x) {cnt[c[et[x]]]++,sum[cnt[c[et[x]]]]++;}
void dec(int x) {sum[cnt[c[et[x]]]]--,cnt[c[et[x]]]--;}
void dfs(int u,int fa) {
et[s[u]=++tick]=u;
for(int i=hd[u],v;i;i=e[i].nxt) {
if((v=e[i].to)==fa) continue;
dfs(v,u);
}
t[u]=tick;
}
signed main() {
n=read(), m=read();
rep(i,1,n) c[i]=read();
rep(i,1,n-1) {
int u=read(), v=read();
add(u,v),add(v,u);
}
dfs(1,0);
bl=sqrt(n);
rep(i,1,n) b[i]=(i-1)/bl+1;
rep(i,1,m) {
int u=read(), k=read();
q[i]=(query){i,s[u],t[u],k};
}
sort(q+1,q+m+1,cmp);
int l=1,r=0;
rep(i,1,m) {
while(l>q[i].l) inc(--l);
while(r<q[i].r) inc(++r);
while(l<q[i].l) dec(l++);
while(r>q[i].r) dec(r--);
ans[q[i].id]=sum[q[i].k];
}
rep(i,1,m) printf("%d
",ans[i]);
return 0;
}
BITSET+莫队
前一篇已经有了一题(掉进兔子洞)。
P3674 小清新人渣的本愿
假设bitset为S,则判断是否有两个数相减为 (x) 的方法为判断 (S&(S<<x)) 是否有1。而加法则可以相反考虑。设存储 (Max_a-a) 的bitset为S2,则判断是否有两个数相加为 (x) 的方法即 (S1&(S2>>(Max_a-a)))。乘法也好做。我们可以枚举每一个约数然后判断是否存在。由于约数个数是 (sqrt a) 级别的,所以可做。
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=1e5+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
int n,m,bl,a[N],b[N],mx,cnt[N],ans[N];
struct query {int id,opt,l,r,x;} q[N];
bool cmp(const query &x,const query &y) {
return b[x.l]==b[y.l]?((b[x.l]&1)?x.r<y.r:x.r>y.r):b[x.l]<b[y.l];
}
bitset<N>bs,ibs;
void inc(int x) {if(++cnt[a[x]]==1) bs[a[x]]=1, ibs[mx-a[x]]=1;}
void dec(int x) {if(--cnt[a[x]]==0) bs[a[x]]=0, ibs[mx-a[x]]=0;}
signed main() {
n=read(), m=read(), bl=pow(n,0.5);
rep(i,1,n) a[i]=read(), b[i]=(i-1)/bl+1;
mx=100000;
rep(i,1,m) q[i].id=i, q[i].opt=read(), q[i].l=read(), q[i].r=read(), q[i].x=read();
sort(q+1,q+m+1,cmp);
int l=1,r=0;
rep(i,1,m) {
while(l>q[i].l) inc(--l);
while(r<q[i].r) inc(++r);
while(l<q[i].l) dec(l++);
while(r>q[i].r) dec(r--);
if(q[i].opt==1) ans[q[i].id]=(bs&(bs<<q[i].x)).any();
else if(q[i].opt==2) ans[q[i].id]=(bs&(ibs>>(mx-q[i].x))).any();
else {
int x=q[i].x;
rep(j,1,sqrt(x)) if(x%j==0&&bs[j]&&bs[x/j]) {ans[q[i].id]=1;break;}
}
}
rep(i,1,m) puts(ans[i]?"hana":"bi");
return 0;
}
P5355 [Ynoi2017] 由乃的玉米田
加了一个除法。考虑根号分治。(xge sqrt mx) 的时候,我们直接和乘法一样暴力枚举即可。 (xle sqrt mx) 时,我们可以 (O(sqrt x n))来算出对于每个 (x),对于每个 (r),满足 ([l,r]) 的答案为 1 的最大的 (l),设其为 (ml_r)。我们算出 (lst_{a_i}) 代表上一个 (a_i) 在哪里。然后我们递推即可。
注意特判乘法和除法 x=0 的情况
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=1e5+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
int n,m,bl,a[N],b[N],mx,cnt[N],ans[N],lst[N],ml[N];
struct query {int id,opt,l,r,x;} q[N];
bool cmp(const query &x,const query &y) {
return b[x.l]==b[y.l]?((b[x.l]&1)?x.r<y.r:x.r>y.r):b[x.l]<b[y.l];
}
bitset<N>bs,ibs;
void inc(int x) {if(++cnt[a[x]]==1) bs[a[x]]=1, ibs[mx-a[x]]=1;}
void dec(int x) {if(--cnt[a[x]]==0) bs[a[x]]=0, ibs[mx-a[x]]=0;}
signed main() {
n=read(), m=read(), bl=pow(n,0.5);
rep(i,1,n) a[i]=read(), b[i]=(i-1)/bl+1;
mx=100000;
rep(i,1,m) q[i].id=i, q[i].opt=read(), q[i].l=read(), q[i].r=read(), q[i].x=read();
sort(q+1,q+m+1,cmp);
int l=1,r=0;
rep(x,1,sqrt(mx)) {
memset(lst,0,sizeof(lst));
memset(ml,0,sizeof(ml));
int l=0;
rep(r,1,n) {
lst[a[r]]=r;
if(a[r]*x<=mx) l=max(l,lst[a[r]*x]);
if(a[r]%x==0) l=max(l,lst[a[r]/x]);
ml[r]=l;
}
rep(i,1,m) if(q[i].opt==4&&q[i].x==x) ans[q[i].id]=(q[i].l<=ml[q[i].r]);
}
rep(i,1,m) {
while(l>q[i].l) inc(--l);
while(r<q[i].r) inc(++r);
while(l<q[i].l) dec(l++);
while(r>q[i].r) dec(r--);
if(q[i].opt==1) ans[q[i].id]=(bs&(bs<<q[i].x)).any();
else if(q[i].opt==2) ans[q[i].id]=(bs&(ibs>>(mx-q[i].x))).any();
else if(q[i].opt==3) {
int x=q[i].x;
if(x!=0) {
rep(j,1,sqrt(x)) if(x%j==0&&bs[j]&&bs[x/j]) {ans[q[i].id]=1;break;}
}
else ans[q[i].id]=bs[0];
} else if(q[i].x>sqrt(mx)) {
int x=q[i].x;
for(int j=1;j*x<=mx;j++) if(bs[j]&&bs[j*x]) {ans[q[i].id]=1;break;}
} else if(q[i].x==0) ans[q[i].id]=bs[0]&&(cnt[0]!=q[i].r-q[i].l+1);
}
rep(i,1,m) puts(ans[i]?"yuno":"yumi");
return 0;
}
带修莫队
本质就是三维莫队。几个变化
1 query结构体还需要存这是第几个版本(第几次修改以后)
2 排序的比较函数需要改为
bool cmp(const query &x,const query &y) {
return b[x.l]==b[y.l]?(b[x.r]==b[y.r]?x.ver<y.ver:x.r<y.r):x.l<y.l;
}
即先判断 l 的块,再判断 r 的块,然后再判断 ver
3 在4个while后面还要再加2个while检查版本是否对。如果版本过老,那么就一路while更新过去;如果版本过新,那么就一路while回退回去。
while(ver<q[i].ver) upd(++ver,i);
while(ver>q[i].ver) rev(ver--,i);
有些情况upd和rev可以并起来写。
4 块长改为 (n^{frac{2}{3}}),复杂度变为 (n^{frac{5}{3}})
P1903 [国家集训队]数颜色
模板题。这道题中upd和rev可以并起来写,因为实指上就是交换被操作序列中的元素和操作队列中的元素。详见代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=1e6+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
int n,m,a[N],bs,b[N],qcnt,rcnt,cnt[N],tot,ans[N];
struct query {int id,l,r,ver;} q[N];
bool cmp(const query &x,const query &y) {
return b[x.l]==b[y.l]?(b[x.r]==b[y.r]?x.ver<y.ver:x.r<y.r):x.l<y.l;
}
struct replc {int p,col;} r[N];
void inc(int x) {tot+=(++cnt[x]==1);}
void dec(int x) {tot-=(--cnt[x]==0);}
void mdf(int ver,int i) {
if(q[i].l<=r[ver].p&&r[ver].p<=q[i].r)
inc(r[ver].col), dec(a[r[ver].p]);
swap(a[r[ver].p],r[ver].col);
}
int main() {
n=read(), m=read(), bs=pow(n,0.66);
rep(i,1,n) a[i]=read(), b[i]=(i-1)/bs+1;
rep(i,1,m) {
char c[3]; scanf("%s",c);
int l=read(), rr=read();
if(c[0]=='Q') q[++qcnt]=(query){qcnt,l,rr,rcnt};
else r[++rcnt]=(replc){l,rr};
}
sort(q+1,q+qcnt+1,cmp);
int l=1,r=0,ver=0;
rep(i,1,m) {
while(l>q[i].l) inc(a[--l]);
while(r<q[i].r) inc(a[++r]);
while(l<q[i].l) dec(a[l++]);
while(r>q[i].r) dec(a[r--]);
while(ver<q[i].ver) mdf(++ver,i);
while(ver>q[i].ver) mdf(ver--,i);
ans[q[i].id]=tot;
}
rep(i,1,qcnt) printf("%d
",ans[i]);
return 0;
}
CF940F Machine Learning
注意到这道题mex可以暴力计算,因为mex不会超过 (sqrt n)。证明:如果mex为 (x),那么就存在出现 (1,2,...,x-1) 次的数,满足 (1+2+...+(x-1)le n),所以必然是 (sqrt n) 级别的。
#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define per(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int N=2e5+9;
inline int read() {
register int x=0, f=1; register char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
return x*f;
}
int n,m,a[N],bs,b[N],qcnt,ccnt,cnt[N],tot[N],ans[N];
struct disc {int id,val;} d[N];
bool cmp(const disc &x,const disc &y) {return x.val<y.val;}
void discrete() {
rep(i,1,n+ccnt) d[i]=(disc){i,a[i]};
sort(d+1,d+n+ccnt+1,cmp);
int cnt=0;
rep(i,1,n+ccnt) a[d[i].id]=(d[i].val==d[i-1].val?cnt:++cnt);
}
struct query {int id,l,r,ver;} q[N];
struct change {int p,val;} c[N];
bool cmp2(const query &x,const query &y) {
return b[x.l]==b[y.l]?(b[x.r]==b[y.r]?x.ver<y.ver:x.r<y.r):x.l<y.l;
}
void inc(int x) {tot[cnt[a[x]]]--,tot[++cnt[a[x]]]++;}
void dec(int x) {tot[cnt[a[x]]]--,tot[--cnt[a[x]]]++;}
void mdf(int x,int i) {
if(q[i].l<=c[x].p&&c[x].p<=q[i].r) {
dec(c[x].p), swap(c[x].val,a[c[x].p]), inc(c[x].p);
} else swap(c[x].val,a[c[x].p]);
}
int main() {
n=read(), m=read(), bs=pow(n,0.66);
rep(i,1,n) a[i]=read(), b[i]=(i-1)/bs+1;
rep(i,1,m) {
int opt=read(), x=read(), y=read();
if(opt==1) q[++qcnt]=(query){qcnt,x,y,ccnt};
else c[++ccnt]=(change){x,y};
}
rep(i,1,ccnt) a[n+i]=c[i].val;
discrete();
rep(i,1,ccnt) c[i].val=a[n+i];
sort(q+1,q+qcnt+1,cmp2);
int l=1,r=0,ver=0;
rep(i,1,qcnt) {
while(l>q[i].l) inc(--l);
while(r<q[i].r) inc(++r);
while(l<q[i].l) dec(l++);
while(r>q[i].r) dec(r--);
while(ver<q[i].ver) mdf(++ver,i);
while(ver>q[i].ver) mdf(ver--,i);
ans[q[i].id]=1;
while(tot[ans[q[i].id]]) ans[q[i].id]++;
}
rep(i,1,qcnt) printf("%d
",ans[i]);
return 0;
}