Look for socks of different && small Z (basic Mo team template)

The sequence is different

Mo's algorithm idea:

(1) Sort m queries: the left endpoint is the first keyword and the right endpoint is the second keyword
(2) Maintain a sequence (pl,pr), and modify pr and pl by adding or subtracting one according to the query interval (l,r) each time
Since the query has been sorted before, the adjustment complexity is very low, close to O (N * sqrt (N))
Note: the initial state pl=1, pr=0 indicates that there is no number in the interval

The details are in the notes

Upper code

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+5;
int n,m;
int a[N],buc[N],bel[N];//a[i] is the input data, and buc[i] is the number of pairs of I (barrels)
//bel[i] is the number of the block to which the ith number belongs, then bel[i]=i/B+1(B is the length of the block)
int len;
long long qans;//qans is the answer (how many pairs of the same number)
/*
The meaning of pans value: there are pans pairs of the same number in the maintained interval
 Possible scenarios for pans values:
(1)pans=0 No same number
(2)pans>0 There are pans for the same number
(3)pans<0 ...According to practical significance, this situation cannot exist
*/
int pl=1,pr=0;
inline void add(int k)
{
	qans+=buc[a[k]]++;
}//Add the k-th point to the maintenance interval: since a[k] and the original buc[a[k]] a[k] in the sequence become the same number of buc[a[k]] pairs, it is written in the above form
//be careful!!!: The meaning of this sentence is to calculate qans+=buc[a[k]], and then buc[a[k]] +;
inline void del(int k)
{
	qans-=--buc[a[k]];
}//Remove the k-th point from the maintenance interval: since a[k] and the original buc[a[k]]-1 a[k] in the sequence become the same number of buc[a[k]]-1 pairs, the writing method is as follows
//The meaning of this sentence is to calculate buc[a[k]]-1 first, and then qans-=buc[a[k]]
inline int calc(int l,int r)//l. R is the target interval
{
	while(pl>l)add(--pl);//When pl > L, move pl to the left and add the contribution of a[pl-1] to the answer pans
	while(pr<r)add(++pr);//When pr < R, move pr to the right and add the contribution of a[pr+1] to the answer pans
	while(pl<l)del(pl++);//When PL < L, move PL to the right and remove the contribution of a[pl] to the answer pans from the pans
	while(pr>r)del(pr--);//When pr > R, move PR to the left and remove the contribution of a[pr] to the answer pans from the pans
	return qans;//Returns the current answer
}
struct ask
{
	int l,r,id;	
}q[N];//Store the left and right endpoints and sequence number of each query 
bool cmp(ask a,ask b)
{
	return bel[a.l]!=bel[b.l] ? a.l<b.l	: a.r<b.r;
}//Sort the queries according to the left endpoint as the first keyword and the right endpoint as the second keyword 
bool ans[N];
int main()
{
	scanf("%d%d",&n,&m);
	len=ceil(sqrt(n));//Round down to get the length of each block 
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		bel[i]=i/len+1;
	}//Block operation: calculate the block number bel[i] of the ith number 
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d",&q[i].l,&q[i].r);
		q[i].id=i;
	}
	sort(q+1,q+m+1,cmp);
	for(int i=1;i<=m;++i)
	{
		int l=q[i].l;
		int r=q[i].r;
		int id=q[i].id;
		ans[id]=!calc(l,r);	
	}
	for(int i=1;i<=m;++i) printf("%s\n",ans[i]?"Yes":"No");
	return 0;
}

P1494 [national training team] little Z's socks
It's no different from the last question
Details:
(1) Simplest fraction: find gcd (maximum common factor) of the numerator denominator and divide the numerator denominator by gcd respectively
(2) Possibility calculation: ans = calc(l,r) / (r-l+1)*(r-l)/2;

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath> 
using namespace std;
const int maxn=5e4+5;
int n, m, qans=0,pl=1,pr=0,bel[maxn],a[maxn],len,buc[maxn], sto, ans[maxn][3];
struct ask
{
	int l,r,id;
}q[maxn];
bool cmp(ask a,ask b)
{
	return bel[a.l]!=bel[b.l] ? a.l<b.l : a.r<b.r;	
}
inline void add(int k)
{
	qans+=buc[a[k]]++;	
}
inline void del(int k)
{
	qans-=--buc[a[k]];		
}
/*
int gcd(long long x,long long y) return y ? gcd(y,x%y) : x;//Add this line without using c++11 
*/
inline int calc(int l,int r)
{
	while(pl>l) add(--pl);
	while(pr<r) add(++pr);
	while(pl<l) del(pl++);
	while(pr>r) del(pr--);
	return qans;	
}
int main()
{
	scanf("%d%d",&n,&m);
	len=ceil(sqrt(n));
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		bel[i]=i/len+1;	
	}
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d",&q[i].l,&q[i].r);
		q[i].id=i;	
	}
	sort(q+1,q+m+1,cmp);
	for(int i=1;i<=m;++i)
	{
		int l=q[i].l, r=q[i].r, id=q[i].id;
		if(l==r)
		{
			ans[id][0]=0;
			ans[id][1]=1;
			continue;		
		}
		ans[id][0]=calc(l,r);
		ans[id][1]=1ll*(r-l+1)*(r-l)/2;
		long long k=__gcd(ans[id][0],ans[id][1]);
		ans[id][0] /= k;
		ans[id][1] /= k;
	}
	for(int i=1;i<=m;++i) printf("%d/%d\n", ans[i][0],ans[i][1]);
	return 0;
}	

Mo team Optimization: parity optimization
It is best to understand the principle according to the image

It can be found that when the left endpoint enters a new interval, the right endpoint needs to return to the leftmost from N, and then run back to the rightmost. This is also a lot of redundant extensions.

A parity optimization scheme is provided:

For odd block numbers, they are arranged in ascending order of p[i].r, whereas even numbers are arranged in descending order of p[i].r. The effects are as follows:

Code implementation:
You only need to modify the code in one place:

If a.l and b.l are in the same block, then:
If the block number is odd, it is arranged according to A.l < b.l;
If the block number is even, it is arranged according to A.l > b.l.
If it is not in the same block, the lower number of the left endpoint is in front.
So the code is:

bool cmp(ask a,ask b)
{
	return bel[a.l] == bel[b.l] ? (bel[a.l] & 1 ? a.r < b.r : a.r > b.r): a.l < b.l;;
}

PS: About parity optimization
This optimization does not reduce the complexity of the algorithm. In essence, constant level optimization makes the actual complexity closer to the ideal complexity O (N*sqrt (N)) of Mo team by reducing unnecessary operations.
But: it seems that parity optimization will only make the code faster and will not make the complexity worse.
Moreover, as an important algorithm, Mo team is likely to be stuck. Therefore, if you can write it correctly, you must write it!!!
What if there are 20 Kamo teams at 25 points? In short, it will be possible to write rp + +. If you don't write, you'll only get stuck.

Take xiumo team
The solution is to add a timeline T

You can add a variable now´╝îIndicates how many modifications have been made before the query currently processed.
For each query, record how many modifications have been made before the current query
#include <bits/stdc++.h>
#define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f , N = 1.4e5+5 , M = 1e6+5;
typedef long long ll;
typedef unsigned long long ull;
inline ll read(){
	ll ret = 0 ; char ch = ' ' , c = getchar();
	while(!(c >= '0' && c <= '9')) ch = c , c = getchar();
	while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
	return ch == '-' ? - ret : ret;
}
int n,m;
int a[N];
int pl=1,pr,pans,len,bel[N];
int buc[M],now;
int ans[N];
struct ask{int l,r,id,t;}q[N];int qcnt;
inline bool operator < (const ask a,const ask b){return bel[a.l] == bel[b.l] ? bel[a.r] == bel[b.r] ? a.t<b.t : a.r<b.r : a.l < b.l;}
struct mdf{int p,v;}mo[N];int mcnt;
inline void mod(int k,int id){
	if(q[id].l <= mo[k].p && mo[k].p <= q[id].r)
		pans += !buc[mo[k].v]++,
		pans -= !--buc[a[mo[k].p]];
	swap(mo[k].v,a[mo[k].p]);
}
inline void add(int k){pans += !buc[a[k]]++;}
inline void del(int k){pans -= !--buc[a[k]];}
inline int calc(int l,int r,int id,int t){
	while(pl > l)add(--pl);
	while(pr < r)add(++pr);
	while(pl < l)del(pl++);
	while(pr > r)del(pr--);
	while(now < t)mod(++now,id);
	while(now > t)mod(now--,id);
	return pans;
}
signed main(){
	n = read() , m = read();
	len = pow(n,2.0/3);
	for(int i = 1 ; i <= n ; i ++)
		a[i] = read(),
		bel[i] = i / len + 1;
	for(int i = 1 ; i <= m ; i ++){
		char ch[2];int x,y;
		scanf(" %s %d %d",ch,&x,&y);
		if(ch[0] == 'Q')q[++qcnt] = (ask){x,y,qcnt,mcnt};
		else mo[++mcnt] = (mdf){x,y};
	}
	sort(q+1,q+qcnt+1);
	for(int i = 1 ; i <= qcnt ; i ++)
		ans[q[i].id] = calc(q[i].l,q[i].r,i,q[i].t);
	for(int i = 1 ; i <= qcnt ; i ++)
		printf("%d\n",ans[i]);
	return 0;
}

Tags: C++ Algorithm

Posted on Thu, 23 Sep 2021 01:42:44 -0400 by buildernaut1