题解——[AHOI2013]作业(莫队)

题解——[AHOI2013]作业(莫队)

有一段时间没写莫队,今天WZB分享这道题,ssw02一看,我可以用莫队水,写的挺快的

欢迎转载ssw02的博客:https://www.cnblogs.com/ssw02/p/11823191.html

题面

给定长为N的序列 , M个询问,每次询问在 下标在[ L , R ]之间 , 数值在 [ a , b ]之间的数的种类和总数 。

N, M都是在1e5 的范围内 。

思路

可以离线,数据支持根号算法,所以我们可以考虑分块 。 总数和如何统计 , 开个桶记录数值的个数 。 每次修改时用一个树状数组维护。支持区间查询即可 。

有一点比较坑人, 之所以种类ssw02也用树状数组维护是因为只有[ a, b ]之间的修改才对当前答案有影响,所以我们不能够直接修改,应为上一次的种类并不能够继承到这次。我们需要重新统计(正好写了树状数组嘛)。另一种方法是在l , r移动的时候顺带处理不合法的贡献,把这些贡献删掉 。 由于数据较小,所以ssw02直接用2个树状数组分别维护2个答案即可 。

代码

#include<bits/stdc++.h>
using namespace std ;
#define ll long long
const int MAXN = 100005 ; 
inline int read(){
	int s=0 ; char g=getchar() ; while( g>'9'||g<'0')g=getchar() ; 
	while( g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s;
}
int N , M , a[MAXN] , tot , block , pos[MAXN] , vis[MAXN]  ;
ll cnt[MAXN] , c[MAXN] , ans[MAXN] , anss[MAXN] ;  
struct ap{
	int l , r , id , a , b ; 
}t[MAXN] ; 
//-----------------
void  add( int x , int y ){
	for( ; x <= N ; x += x&-x )c[x] += y ; 
}
void  add2( int x, int y ){
	for( ; x <= N ; x += x&-x )vis[x] += y ; 
}
ll ask_sum( int x ){
	ll  tott = 0LL ; 
	for( ; x ; x -= x&-x )
	    tott += c[x] ;  
	return tott ; 
}
ll ask_col( int x ){
	ll tott = 0LL ; 
	for( ; x ; x -= x&-x )tott += vis[x] ; 
	return tott ;
}
//-----------------
inline bool cmp( ap x , ap y ){
	return ( pos[x.l] == pos[y.l] )?(x.r < y.r):(pos[x.l] < pos[y.l] ) ;
}
void  updata( int u , int opt , int now ){
	if( opt ){
		if( cnt[a[u]] == 0 )add2( a[u] , 1 ) ;
		cnt[ a[u] ]++ ; add( a[u] , 1 ) ;  
		return ;
	}
	else {
		if( cnt[a[u]] == 1 )add2( a[u] , -1 ) ;
		cnt[ a[u] ]-- ; add( a[u] , -1 ) ;
	}
}
ll  ask( int l , int  r , int opt ){
	if(opt)return ask_sum( r ) - ask_sum( l-1 ) ; 
	else return ask_col( r ) - ask_col( l-1 ) ; 
}
void  Mo(){
	for( int i = 1 , l = 1 , r = 0  ; i <= M ; ++i ){
		while( t[i].l > l )updata( l++ , 0 , i ) ; 
		while( t[i].l < l )updata( --l , 1 , i ) ; 
		while( t[i].r > r )updata( ++r , 1 , i ) ; 
		while( t[i].r < r )updata( r-- , 0 , i ) ; 
		//for( int k = 1 ; k <= N ; ++k )cout<<c[k]<<" "; cout<<endl ;  
		anss[ t[i].id ] = ask( t[i].a , t[i].b , 0 ) , ans[ t[i].id ] = ask( t[i].a , t[i].b , 1 ) ;
	}
}
int main(){
	N = read() , M = read() , block = sqrt(N) ;
	for( int i = 1 ; i <= N ; ++i )a[i] = read() , pos[i] = ( i-1 )/block+1 ;  
	for( int i = 1 ; i <= M ; ++i ){
		t[i].l = read() , t[i].r = read() , t[i].a = read() , t[i].b = read() ,  t[i].id = i ;
	}
	sort( t+1 , t+M+1 , cmp ) ; 
	Mo() ; 
	for( int i = 1 ; i <= M ; ++i )
	    printf("%lld %lld\n",ans[i],anss[i]) ; 
}
posted @ 2019-11-08 20:48  蓝银杏-SSW  阅读(171)  评论(0编辑  收藏  举报
//结束