• 普通莫队学习


    学习资料

    ouuan's blog


    板子化代码参考

    
    int B=n/sqrt(m);//n是序列长度, m是询问数
    struct qs{
    	//“询问”的结构体
    	int id,l,r;//id表示询问编号, l、r分别表示询问区间的左右端点
    	bool operator<(const qs& b) const{
    		return l/B==b.l/B ? r<b.r : l<b.l;
    	}
    }q[maxn];
    int l=1,r=0;//初始区件
    // ------------------------------
    void add(int x) {
    	//balabala
    }
    void del(int x) {
    	//balabala
    }
    void mov(int i) {
    	//询问区间的转移
    	while(l<q[i].l) del(a[l++]);
    	while(l>q[i].l) add(a[--l]);
    	while(r<q[i].r) add(a[++r]);
    	while(r>q[i].r) del(a[r--]);
    }
    
    // + + +
    // in the main function
    // - - -
    	sort(q,q+m);
    	for(int i=0;i<m;++i) {
    		mov(i);//注意初始区间是 [1,0]
    		/*
    			记录答案
    			ans[q[i].id] = balabala
    		*/
    	}
    	for(int i=0;i<m;++i) printf("%d
    ", ans[i]);
    

    普通莫队题目浅解

    小Z的袜子

    询问区间改变的时候,可以 (O(1)) 改变答案, 不带修, 可离线, 可用普通莫队。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 51005;
    
    int n,m,col[maxn];
    int B;
    struct qs{
    	int id,l,r;
    	bool operator<(const qs& b) const {
    		return l/B==b.l/B ? r<b.r : l<b.l;
    	}
    } q[maxn];
    
    int l=1,r=0;
    int fz,fm;
    int len,cnt[maxn];
    void add(int x) {
    	fz+=cnt[x];
    	++cnt[x];
    	fm+=len;
    	++len;
    }
    void del(int x) {
    	--cnt[x];
    	fz-=cnt[x];
    	--len;
    	fm-=len;
    }
    void mov(int i) {
    	while(l<q[i].l) del(col[l++]);
    	while(l>q[i].l) add(col[--l]);
    	while(r<q[i].r) add(col[++r]);
    	while(r>q[i].r) del(col[r--]);
    }
    
    int ans[maxn][2];
    int gcd(int a,int b) {
    	return (!b) ? a : gcd(b,a%b);
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	B = n/sqrt(m);
    	for(int i=1;i<=n;++i) scanf("%d",&col[i]);
    	for(int i=0;i<m;++i) {
    		scanf("%d%d",&q[i].l,&q[i].r);
    		q[i].id=i;
    	}
    	sort(q,q+m);
    	for(int i=0;i<m;++i) {
    		mov(i);
    		if(q[i].l==q[i].r) {
    			ans[q[i].id][0]=0;
    			ans[q[i].id][1]=1;
    			continue;
    		}
    		int g=gcd(fz,fm);
    		ans[q[i].id][0]=fz/g;
    		ans[q[i].id][1]=fm/g;
    	}
    	for(int i=0;i<m;++i) printf("%d/%d
    ",ans[i][0],ans[i][1]);
    	return 0;
    }
    

    小B的询问

    询问可离线且不带修
    设数 (k) 在区间 ([L,R]) 中出现了 (cnt_k) 次,对答案的贡献即为 ((cnt_k)^2) 每当 (cnt_k)(1) 时, 贡献变为 ((cnt_k+1)^2 = (cnt_k)^2 + 2*cnt_k + 1), 即答案增加 (2*cnt_k + 1)(cnt_k) 减一的情况类似。
    区间发生 (1) 单位变动答案可 (O(1)) 转换
    可以使用普通莫队求解。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 51005;
    int n,m,k,a[maxn];
    
    int B;
    struct qs{
    	int id,l,r;
    	bool operator<(const qs& b) const{
    		return l/B==b.l/B ? r<b.r : l<b.l;
    	}
    }q[maxn];
    int ans[maxn];
    
    int l=1,r=0,cnt[maxn],sum;
    void add(int x) {
    	sum+=(2*cnt[x]+1);
    	++cnt[x];
    }
    void del(int x) {
    	--cnt[x];
    	sum-=(2*cnt[x]+1);
    }
    void mov(int i) {
    	while(l<q[i].l) del(a[l++]);
    	while(l>q[i].l) add(a[--l]);
    	while(r<q[i].r) add(a[++r]);
    	while(r>q[i].r) del(a[r--]);
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&k), B=n/sqrt(m);
    	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    	for(int i=0;i<m;++i) scanf("%d%d",&q[i].l,&q[i].r), q[i].id=i;
    	sort(q,q+m);
    	for(int i=0;i<m;++i) {
    		mov(i);
    		ans[q[i].id] = sum;
    	}
    	for(int i=0;i<m;++i) printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Vue.js学习笔记(8)拖放
    Vue.js学习笔记(7)组件详解
    使用了与请求的协议不兼容的地址的解决办法
    修改machine.config遇到System.Net.ServicePointManager 的类型初始值设定项引发异常
    未找到路径“/Agent/SissQrTemplate/AddN”的控制器或该控制器未实现 IController。
    C# .NET 2.0 判断当前程序进程是否为64位运行时 (x64)
    荣耀9开启虚拟按键
    C# .NET 4.5 将多个文件添加到压缩包中
    开IE时 暴卡
    VMware Workstation 安装 mac OS 时遇到 不可恢复错误: (vcpu-0)
  • 原文地址:https://www.cnblogs.com/tztqwq/p/12993084.html
Copyright © 2020-2023  润新知