莫队学习(别看)

学习博客:https://www.cnblogs.com/Paul-Guderian/p/6933799.html

适用范围:

离线,简单修改,O1或Ologn求附近区间

只有查询:

bzoj2038 莫队+概率+逆元                 N种袜子,给若干区间问取到两只相同袜子的概率

sum(C(a,2))/C(区间长度,2)

维护sum[]每种袜子的数目,转移的时候直接减去整个a^2后在加上去

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=5e4+5;
struct mo{
	ll l,r,id,a,b;
}q[maxn]; 
int bel[maxn];
int col[maxn];
ll sum[maxn];
ll ans=0;
bool cmp(mo a,mo b)
{
	if(bel[a.l]==bel[b.l])return a.r<b.r;
	return a.l<b.l;
}
bool cmp2(mo a,mo b){return a.id<b.id;}
inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f; 
}
void fuck(int idx,int add)
{
	ans-=sum[idx]*sum[idx];
	sum[idx]+=add;
	ans+=sum[idx]*sum[idx];
}
int main()
{
	int n,m;ans=0;
	n=read();m=read();
	int unit=sqrt(n);
	for(int i=1;i<=n;i++)
	{
		col[i]=read();
		bel[i]=i/unit+1;
	}
	for(int i=1;i<=m;i++)
	{
		q[i].l=read();q[i].r=read();q[i].id=i;
	}
	sort(q+1,q+1+m,cmp);
	int L=1,R=0;
	for(int i=1;i<=m;i++)
	{
		while(L<q[i].l)fuck(col[L],-1),L++;
		while(L>q[i].l)fuck(col[L-1],1),L--;
		while(R<q[i].r)fuck(col[R+1],1),R++;
		while(R>q[i].r)fuck(col[R],-1),R--;
		if(q[i].l==q[i].r)
		{
			q[i].a=0,q[i].b=1;
			continue;
		}
		q[i].a=ans-(q[i].r-q[i].l+1);
		q[i].b=(q[i].r-q[i].l+1)*(q[i].r-q[i].l);
		ll gcd=__gcd(q[i].a,q[i].b);
		q[i].a/=gcd;q[i].b/=gcd;
	}
	sort(q+1,q+1+m,cmp2);
	for(int i=1;i<=m;i++)
	{
		printf("%lld/%lld\n",q[i].a,q[i].b);
	}
	
}

hdu3333   莫队+离散化  求区间l,r的加法和,相同的只加一次

hdu3874   莫队               求区间l,r的加法和,相同的只加一次

注意预处理离散化后的数组mp,每次都二分会T

#include<bits/stdc++.h>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define ll long long 
using namespace std;
const int maxn=30005;
int bel[maxn];int col[30005];ll a[maxn];ll res[100005];int rk[30005],rn; 
int mp[maxn];
ll ans=0;int n;int T;int l=1,r=0;int m;
struct mo{int id,l,r;}q[100005]; 

void setrk(int n){//调用前,所有y值被无序存入rk数组,下标为[1..rn]   
	rn=n;int idx=1;  
    sort(rk+1,rk+1+rn); //第一步排序   
    for(int i=2;i<=rn;++i) if(rk[i]!=rk[i-1]) rk[++idx]=rk[i];  //第二步去除重复值 
    rn=idx;  
    //此时,所有y值被从小到大无重复地存入rk数组,下标为[1..rn]   
} 
int getrk(int x) { return lower_bound(rk+1,rk+1+rn,x)-rk;}


bool cmp(mo a,mo b){ if(bel[a.l]==bel[b.l])return a.r<b.r;return a.l<b.l; }
bool cmp2(mo a,mo b){ return a.id<b.id; }
void revise(int x,int idx,int d){ col[mp[idx]]+=d; if(d>0)ans+=1ll*(col[mp[idx]]==1)*x; if(d<0)ans-=1ll*(col[mp[idx]]==0)*x;}



inline ll read(){
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;	
} 

int main()
{
	
	T=read();
	while(T--)
	{
		ans=0;l=1;r=0;
		memset(col,0,sizeof(col));
		n=read();int unit=(int)sqrt(n);
		for(int i=1;i<=n;i++)		a[i]=read(),rk[i]=a[i],bel[i]=i/unit+1;	
		m=read();setrk(n);
		for(int i=1;i<=n;i++) mp[i]=getrk(a[i]);
		for(int i=1;i<=m;i++)       q[i].id=i,q[i].l=read(),q[i].r=read();
		sort(q+1,q+1+m,cmp);
		for(int i=1;i<=m;i++)
		{
			while(l<q[i].l)revise(a[l],l,-1),l++;
			while(l>q[i].l)revise(a[l-1],l-1,1),l--;
			while(r<q[i].r)revise(a[r+1],r+1,1),r++;
			while(r>q[i].r)revise(a[r],r,-1),r--;
			res[q[i].id]=ans;
			//printf("test:%d\n",ans);
		}
		for(int i=1;i<=m;i++)
			printf("%I64d\n",res[i]);
	} 
}


带单点修改

BZOJ2120


树上莫队

不会



猜你喜欢

转载自blog.csdn.net/animalcoder/article/details/79921001
今日推荐