20221005多校联训

T1 CF1252G Performance Review

一个公司有 \(n\) 个员工,每个员工有一个能力值 \(a_i\), 每个 \(a_i\) 都不一样。公司采取末位淘汰制,我们考虑 \(m\) 年,每年年底都会补充 \(r_i\) 个新员工,每个新员工的能力值被表示为 \(b_{ij}\), 即第 \(i\) 年新加入的第 \(j\) 个员工的能力值。每年,能力值最靠后的 \(r_i\) 个员工会被炒鱿鱼,取而代之的是新加入的这 \(r_i\) 个员工。你是第 \(1\) 号员工,你的能力值是 \(a_1\)
还有 \(q\) 次操作,每次操作的描述形如 \((x_i,y_i,z_i)\), 表示把第 \(x_i\) 年加入的第 \(y_i\) 个员工的能力值改为 \(z_i\)。 现在对于每个操作输出 \(0\)\(1\),表示如果进行完这个操作,\(m\) 年之后你会不会被炒鱿鱼。注意,操作是永久性的。

注意到,对于当前数列中的所有数,可以简单地将它们分为两类,即大于 \(a_1\) 的一类和小于 \(a_1\) 这一类。这两类数决定了 \(a_1\) 在当前数列中的排名,影响着它是否会被炒鱿鱼。

那么,我们只需要关注每个时刻数列中比 \(a_1\) 小的数的个数和当前时刻会炒多少人的鱿鱼的关系。如果前者小于后者,那么就会被炒鱿鱼。

题目中还有修改操作,对于第 \(x\) 年某个值的修改操作可能会影响到 \([x,m]\) 这个范围年份中比 \(a_1\) 小的数的数量。显然这是一个区间修改操作,考虑用线段树来维护 \(a_i\) 的排名。

对于一次修改,如果修改之前的数小于 \(a_1\),且修改后的数大于 \(a_1\),那么在 \(x\) 年后,比 \(a_1\) 小的数的数量都减一。反之,如果修改之前的数大于 \(a_1\),且修改之后的数小于 \(a_1\),那么在 \(x\) 年后,比 \(a_1\) 小的数的数量都加一。令第 \(k\) 年比 \(a_1\)小的数的数量为 \(p[k]\)。我们在线段树中还应该记录一个 \(p[k] - r[k]\) 的最小值 \(mn\)。如果在整个区间中,\(mn\) 的最小值小于 \(0\),那么你就会被开除,反之则不会。

代码:

#include<bits/stdc++.h>
#define ll (i<<1)
#define rr (i<<1) + 1
#define mid (tl + tr) / 2
using namespace std;
const int MAXN = 1e5;
int n,m,a[MAXN + 5],q;
vector<int> ins[MAXN + 5];
int cnt;
struct node{
	int lazy,num,mn;
}tree[MAXN * 4 + 20];
void build(int i,int tl,int tr){
	if(tl == tr){
		tree[i].num = cnt;
		return;
	}
	build(ll,tl,mid);
	build(rr,mid + 1,tr); 
}
void push_down(int i){
	tree[ll].lazy += tree[i].lazy;
	tree[rr].lazy += tree[i].lazy;
	tree[ll].mn += tree[i].lazy;
	tree[rr].mn += tree[i].lazy;
	tree[i].lazy = 0;
}
void change(int i,int tl,int tr,int l,int r,int k){
	if(tl > r || tr < l)return;
	if(tl >= l && tr <= r){
		tree[i].mn += k;
		tree[i].lazy += k;
		return;
	}
	push_down(i);
	change(ll,tl,mid,l,r,k);
	change(rr,mid + 1,tr,l,r,k);
	tree[i].mn = min(tree[ll].mn,tree[rr].mn);
}
int b[MAXN + 5];
int query(int i,int tl,int tr,int p){
	if(tl == tr){
		tree[i].num += tree[i].lazy;
		tree[i].lazy = 0;
		tree[i].mn = tree[i].num - b[tl];
		return tree[i].num;
	}
	push_down(i);
	int ans;
	if(p > mid)ans = query(rr,mid + 1,tr,p);
	else ans = query(ll,tl,mid,p);
	tree[i].mn = min(tree[ll].mn,tree[rr].mn);
}

int main(){
//	freopen("a3.in","r",stdin);
//	freopen("ans","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> q;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		if(i != 1 && a[i] < a[1])cnt++;
	}
	build(1,1,m);
	for(int i = 1; i <= m;i++){
		cin >> b[i];
		int c;
		cnt = 0;
		for(int j = 1; j <= b[i];j++){
			cin >> c;
			ins[i].push_back(c);
			if(c < a[1])cnt++;
		}
		int p = query(1,1,m,i);
		c = cnt - b[i];
		change(1,1,m,i + 1,m,c);
	}
	for(int i = 1; i <= m; i++)int p = query(1,1,m,i);
	int x,y,z;
	int now = 1;
	for(int i = 1; i <= q; i++){
		cin >> x >> y >> z;
		if(ins[x][y - 1] < a[1] && z > a[1])change(1,1,m,x + 1,m,-1);
		else if(ins[x][y - 1] > a[1] && z < a[1])change(1,1,m,x + 1,m,1);
		bool flag = 0;
		int k = query(1,1,m,1);
		k = query(1,1,m,m);
		if(tree[1].mn < 0)cout << "0\n";
		else cout << "1\n";
		ins[x][y - 1] = z;
	}
} 
//5 3 3
//50 40 30 20 10
//4 1 2 3 100
//1 4
//2 6 7
//1 3 300
//2 1 400
//2 1 52 
posted @ 2022-10-06 18:52  腾云今天首飞了吗  阅读(24)  评论(0编辑  收藏  举报