JOISC 2016 Day 2雇佣计划

前置技能:树状数组

切分,相信大家都会写的。

题解部分:

题目就是让我们求能力值大于等于B的人构成的联通块的个数。

假设一开始有一片平原,然后在平原上一个位置对应一个人。对于每一次询问,如果一个人的能力值满足要求,他就会形成一座山,如果不行就还是平原。

假设一次询问后,这片地方是这样的:(假设询问的B为4)

QWQ

我们可以发现,联通块的数量就是沟壑的数量除以2,而分析每一个沟壑,我们可以知道它出现的时间。假设一个沟壑对应两边能力值较小的人的能力值为X,对应两边能力值较大的人的能力值为Y,那么如果询问的B在X+1到Y这个范围内时,这个沟壑就会存在。我们可以用树状数组来维护这个东西。每次修改在树状数组里修改就是了。

注意我们要计算最左边和最右边的沟壑(可以理解为就是第1个人与第0个人之间的沟壑,同理的还有第n个人与第n+1个人之间的沟壑)。

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 200005
#define lowbit(x) x&-x
using namespace std;
struct Que{
	int op,x,y;
	bool operator <(const Que &_)const{
		return x<_.x;
	}
}Q[M];
int n,m;
int val[M];
int B[M<<2],sz;
int Get_num(int x){return lower_bound(B+1,B+sz+1,x)-B;}
void Init(){
	for(int i=1;i<=n;i++)B[++sz]=val[i];
	for(int i=1;i<=m;i++)if(Q[i].op==2)B[++sz]=Q[i].y;
	else B[++sz]=Q[i].x;
	sort(B+1,B+sz+1);
	sz=unique(B+1,B+sz+1)-B-1;
	for(int i=1;i<=n;i++)val[i]=Get_num(val[i]);
	for(int i=1;i<=m;i++){
		if(Q[i].op==2)Q[i].y=Get_num(Q[i].y);
		else Q[i].x=Get_num(Q[i].x);
	}
}
struct Bin{
	int num[M<<2];
	void clear(){
		memset(num,0,sizeof(num));
	}
	void Add(int x,int d){
		x++;//x可能等于0 
		while(x<(M*3)){
			num[x]+=d;
			x+=lowbit(x);
		}
	}
	int sum(int x){
		x++;
		int res=0;
		while(x){
			res+=num[x];
			x-=lowbit(x);
		}
		return res;
	}
}BT;
void Updata(int i,int op){
	int L=val[i-1],R=val[i];
	if(L>R)swap(L,R);
	L++;
	BT.Add(L,op);BT.Add(R+1,-op);
	L=val[i],R=val[i+1];
	if(L>R)swap(L,R);
	L++;
	BT.Add(L,op);BT.Add(R+1,-op);
}
void Solve(){
	Init();//离散化 
	BT.clear();
	for(int i=1;i<=n+1;i++){//沟壑(包含最左边和最右边的) 这里假设第0个人与第n+1个人的能力值为0 
		int L=val[i-1],R=val[i];
		if(L>R)swap(L,R);
		L++;
		BT.Add(L,1);BT.Add(R+1,-1); 
	}
	for(int i=1;i<=m;i++){
		if(Q[i].op==1){
			int ans=BT.sum(Q[i].x)/2;//答案数量为沟壑数量/2 
			printf("%d\n",ans);
		}else {
			Updata(Q[i].x,-1);//在树状数组上更新 
			val[Q[i].x]=Q[i].y;
			Updata(Q[i].x,1);
		}
	}
}
int main(){
	freopen("plan.in","r",stdin);
	freopen("plan.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&val[i]);
	for(int i=1;i<=m;i++){
		scanf("%d",&Q[i].op);
		if(Q[i].op==1)scanf("%d",&Q[i].x);
		else scanf("%d%d",&Q[i].x,&Q[i].y);
	}
	Solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35320178/article/details/89181661
今日推荐