• 莫队学习笔记2


    前一篇: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;
    }
    
  • 相关阅读:
    Web性能优化系列(3):如何延迟加载JS
    Web性能优化系列(2):剖析页面绘制时间
    Web性能优化系列(1):Web性能优化分析
    页面制作之开发调试工具(1)
    格式化 SQL 来提高效率
    关于SQL注入,你应该知道的那些事
    jQuery()方法的第二个参数
    JSON简介以及用法代码汇总
    js简单的面试题
    常用meta整理
  • 原文地址:https://www.cnblogs.com/TetrisCandy/p/14274579.html
Copyright © 2020-2023  润新知