4405: 招生

链接

[http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4405]

题意

浙江理工大学招生,一开始有0名学生报考,现在有如下几种情况;

1.增加一名报考学生,报考学生成绩为x;

2.一名成绩为x的学生放弃报考。

3.从现在报考的学生来看,老师想知道如果要招生至少x名学生,需要将分数线最高设置为多少;

4.从现在报考的学生来看,如果分数线设置为x,能有几名学生被录取。

第一行先输入一个n,表示有n次操作或查询;

接下来n行,每行输入两个整数opt和x(用空格隔开):

如果opt为1,则增加一名报考学生,报考学生成绩为x;

如果opt为2,则表示一名成绩为x的学生放弃报考。

如果opt为3,从现在报考的学生来看,老师想知道如果要招生至少x名学生,需要将分数线最高设置为多少,输出最高分数线。

如果opt为4,从现在报考的学生来看,如果分数线设置为x,能有几名学生被录取,输出录取人数。

对于每个输出占一行。

n不超过50000;0<=x<=1000000;1<=k<=现在的学生数。

Input
第一行输入一个n,接下来n行,每行输出两个整数opt,x,用空格隔开

Output
对于每次输出, 输出一个整数占一行

Sample Input
18
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
2 8
3 2
3 3
3 4
3 5
4 8
4 9
4 7
Sample Output
11
10
9
7
4
4
5

分析

树状数组 思路转换

代码

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e6+50;
int c[N];//c[N]覆盖的子节点(子节点代表的是分数)的人数
void add(int x,int value){
	while(x<N){
		c[x]+=value;
		x+=(x&-x);
	}
} 
int sum(int x){//分数小于x的人数 
   int ans=0; 
	while(x){
		ans+=c[x];
		x-=(x&-x);
	}
	return ans;
}
int solve(int x){//最多招x人所能设置的最高分数线 
	int pos=0;
	for(int i=19;i>-1;i--)//1<<20=1048576 > 1e6
	if(x>=c[pos+(1<<i)]){
		x-=c[pos+(1<<i)];
		pos+=(1<<i);
	}
	return pos;
}
int main(){
	int n,op,x,cnt=0;
	//freopen("in.txt","r",stdin);
	scanf("%d",&n);
	while(n--){
		scanf("%d%d",&op,&x);
		if(op==1){
			add(x+1,1);
			cnt++;
		}
		else if(op==2){
			add(x+1,-1);
			cnt--;
		}
		else if(op==3)
		printf("%d\n",solve(cnt-x));//至少招x人和最多招cnt-x人是等价的 
		else printf("%d\n",cnt-sum(x));
	}
	return 0;
}
posted @ 2018-11-07 14:13  ChunhaoMo  阅读(119)  评论(0)    收藏  举报