资讯详情

CF220B Little Elephant and Array(扫描线+树状数组)

原题链接

思路:

首先,我们可以先将所有的询问进行离线,区间问题借助扫描线的思想,枚举右端点,计算左端点产生的贡献。 什么时候考虑范围是一个合法的范围,比如当前的数字 x x x,如果 x x x前面有 x ? 1 x-1 x?1个 x x x都在范围内,而且这个 x x x前面的第 x x x个 x x x不在区间内,这个区间就是合法区间。 举一个很典型的例子, [ 2 , 2 , 2 , 2 ] [2,2,2,2] [2,2,2,2] 当右端点为 1 1 1当时,整个数组的贡献是 [ 0 , 0 , 0 , 0 ] [0,0,0,0] [0,0,0,0]; 当右端点为 2 2 2当时,整个数组的贡献是 [ 1 , 0 , 0 , 0 ] [1,0,0,0] [1,0,0,0]; 当右端点为 3 3 3时,整个数组产生的贡献为 [ − 1 , 1 , 0 , 0 ] [-1,1,0,0] [−1,1,0,0]; 当右端点为 4 4 4时,整个数组产生的贡献为 [ 0 , − 1 , 1 , 0 ] [0,-1,1,0] [0,−1,1,0]; 具体有什么规律呢,首先对于遍历到的右端点先将其出现的次数加 1 1 1,假设此时出现的数为 x x x,那么这个数前面从右往左出现的第 x x x个位置 + 1 +1 +1,第 x + 1 x+1 x+1个位置 − 2 -2 −2,第 x + 2 x+2 x+2个位置 + 1 +1 +1. 观察右端点从 3 − > 4 3->4 3−>4的过程也可以看出这点,简单说一下理由: 当右端点为 4 4 4时,我们计算出来的前缀和数组应该为 [ 0 , − 1 , 0 , 0 ] [0,-1,0,0] [0,−1,0,0],此时的合法区间为 [ 3 , 4 ] [3,4] [3,4],那么 s u m [ 4 ] − s u m [ 3 − 1 ] = 1 sum[4]-sum[3-1]=1 sum[4]−sum[3−1]=1,符合题意;而 [ 2 , 4 ] [2,4] [2,4]为不合法区间, s u m [ 4 ] − s u m [ 2 − 1 ] = 0 sum[4]-sum[2-1]=0 sum[4]−sum[2−1]=0,也同样符合题意。 用理论也可以解释: 对于从左向右出现的第 x x x个位置,将他的贡献从 0 0 0变为 1 1 1,是因为这时候已经满足 x x x出现了 x x x次。 对于第 x + 1 x+1 x+1个位置,由于计算上一个 x x x的贡献时候,他的贡献已经被改成 1 1 1了,所以要将他的贡献改成 − 1 -1 −1。 对于第 x + 2 x+2 x+2个位置,由于计算上一个合法 x x x的区间的时候,他的贡献被改成 − 1 -1 −1了,但其实他的贡献应该为 0 0 0。 具体做法为: 1. 1. 1.将所有询问离线下来,并且记录每个数出现的位置。 2. 2. 2.枚举右端点,按照上述规律去维护贡献。 3. 3. 3.求前缀和后记录答案。 还有一个问题就是, a [ i ] a[i] a[i]的范围是 1 e 9 1e9 1e9,如果直接对每个数都存出现的位置的话,空间也不允许。但是因为只有出现次数大于本身的值的数才有可能产生贡献,而 n < = 1 e 5 n<=1e5 n<=1e5,所以 a [ i ] > = n a[i]>=n a[i]>=n的数永远不会产生贡献,就可以忽略不计了。

代码:

// Problem: B. Little Elephant and Array
// Contest: Codeforces - Codeforces Round #136 (Div. 1)
// URL: http://codeforces.com/problemset/problem/220/B
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// Author:Cutele
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PLL;
typedef pair<int, int>PII;
typedef pair<double, double>PDD;
#define I_int ll
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;}

inline void write(ll x){ 
        if (x < 0) x = ~x + 1, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0');}

#define read read()
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)

ll ksm(ll a, ll b,ll mod){ 
        ll res = 1;while(b){ 
        if(b&1)res=res*a%mod;a=a*a%mod;b>>=1;}return res;}

const int maxn=1e5+7;

int a[maxn],n,m,ans[maxn],tr[maxn];
vector<PII>q[maxn];
vector<int>g[maxn];

int lowbit(int x){ 
        
	return x&-x;
}
void update(int pos,int val){ 
        
	while(pos<=n){ 
        
		tr[pos]+=val;pos+=lowbit(pos);
	}
}
int query(int pos){ 
        
	int res=0;
	while(pos){ 
        
		res+=tr[pos];pos-=lowbit(pos);
	}
	return res;
}

int main(){ 
        
	n=read,m=read;
	rep(i,1,n) a[i]=read;
	rep(i,1,m){ 
        
		int l=read,r=read;
		q[r].push_back({ 
        l,i});
	}	
	rep(i,1,n){ 
        
		int x=a[i];
		if(x<=n){ 
        
			g[x].push_back(i);
			int siz=g[x].size();
			if(siz>=x){ 
        
				update(g[x][siz-x],1);
				if(siz-x-1>=0) update(g[x][siz-x-1],-2);
				if(siz-x-2>=0) update(g[x][siz-x-2],1);
			}
		}
		for(int j=0;j<q[i].size();j++){ 
        
			PII t=q[i][j];
			int l=t.first,id=t.second;
			ans[id]=query(i)-query(l-1);
		}
	}
	
	rep(i,1,m) printf("%d\n",ans[i]);
	
	
	return 0;
}

标签: 二极管db220b

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台