牛客練習賽73 D題:離別

Zwx2333發表於2020-11-23

題目

題意:

給定一個長度為n的區間 ( n ≤ 300000 ) (n\leq 300000) (n300000),區間中每個數 a [ i ] ≤ n a[i]\leq n a[i]n,進行下列操作:給定一個區間l,r,問[l,r]的範圍有多少個子區間滿足區間眾數等於k。

題解:

首先我們可以預處理出以i為左區間的滿足條件的r的範圍(這裡用雙指標預處理出mi[i],ma[i]。mi是滿足條件的最小的r,ma是滿足條件的最大的r)。
然後我們把查詢區間按照以l為第一關鍵字降序排列,然後對把l+1到n以每個點滿足條件的範圍進行區間修改。最後區間查詢。

md,線段樹區間查詢在更新操作時忘記下放lazytag了,雙指標那也寫掛了幾次,卡了幾個小時。

AC程式碼:
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define rep(i,a,n)  for(int i=a;i<=n;i++)
#define pb push_back
const ll mod=1e9+7;
using namespace std;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b){ll ret=1; while(b){if(b&1)ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret;}
const int N=3e5+5;
ll n,m,k,cnt[N],a[N],ma[N],mi[N],ans[N],b[4*N],d[4*N];
inline ll read(){
    ll num=0,neg=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')neg=-1;c=getchar();}
    while(isdigit(c)){num=(num<<3)+(num<<1)+c-'0';c=getchar();}
    return num*neg;
}
struct node{
	int l,r,pos;
	bool operator<(const node &x){
		return l>x.l; 
	}
}q[N];
void pushdown(int s,int t,int p){
	int mid=(s+t)/2;
	d[p<<1]+=(ll)(mid-s+1)*b[p];d[p<<1|1]+=(ll)(t-mid)*b[p];
	b[p<<1]+=b[p];b[p<<1|1]+=b[p];
	b[p]=0;
}
void pushup(int p){
	d[p]=d[p<<1]+d[p<<1|1];
}
void update(int s,int t,int p,int l,int r,int w){
	if(l<=s&&t<=r){
		d[p]+=(ll)(t-s+1)*(ll)w;
		b[p]+=w;
		return ;
	}
	if(b[p])	pushdown(s,t,p);
	int mid=(s+t)/2;
	if(l<=mid)	update(s,mid,p<<1,l,r,w);
	if(r>mid)	update(mid+1,t,p<<1|1,l,r,w);
	pushup(p);
}
ll query(int s,int t,int p,int l,int r){
	if(l<=s&&t<=r){
		return d[p];
	}
	if(b[p])	pushdown(s,t,p);
	ll ans=0;
	int mid=(s+t)/2;
	if(l<=mid)	ans+=query(s,mid,p<<1,l,r);
	if(r>mid)	ans+=query(mid+1,t,p<<1|1,l,r);
	return ans;
}
int main(){
	n=read();m=read();k=read();rep(i,1,n) a[i]=read();
	int tmp=0;
	for(int l=1,r=1;r<=n;r++){
		cnt[a[r]]++;
		if(cnt[a[r]]==k)	tmp++;
		while(cnt[a[r]]==k+1&&l<=r){
			ma[l]=r-1;
			if(cnt[a[l]]==k)	tmp--;
			cnt[a[l]]--;
			l++;
		}
		if(r==n){
			while(tmp){
				ma[l]=r;
				if(cnt[a[l]]==k)	tmp--;
				cnt[a[l]]--;
				l++;
			}
		}
	}
	memset(cnt,0,sizeof cnt);
	for(int l=1,r=1;r<=n;r++){
		cnt[a[r]]++;
		if(cnt[a[r]]==k){
			while(l<=r){
				cnt[a[l]]--;
				l++;
				mi[l-1]=r;
				if(cnt[a[r]]!=k)	break;	
			}
		}
	}
	for(int i=1;i<=m;i++){
		scanf("%d %d",&q[i].l,&q[i].r);q[i].pos=i;
	}
	sort(q+1,q+1+m);
	int x=n;
	for(int i=1;i<=m;i++){
		int l=q[i].l,r=q[i].r,pos=q[i].pos;
		while(x>=l){
			if(mi[x]==0){
			x--;continue;
			}
			update(1,n,1,mi[x],ma[x],1);
			x--;
		}
		ans[pos]=query(1,n,1,l,r);
	}
	rep(i,1,m)	printf("%lld\n",ans[i]);
	return 0;
}
/*

  */

相關文章