2019 ICPC Asia Jakarta Regional Contest G. Performance Review 线段树

原题链接:https://codeforces.ml/contest/1252/problem/G

题意

一个公司有n个人,每年有若干个人应聘,每次都会开除排名倒数的若干个人并将所有应聘的人招进公司,接下来有q次修改,每次可以修改每年应聘人的能力值,并询问1号员工能否在m年后仍然在公司

分析

如果直接暴力去模拟肯定是不行的,因为O(qm)的复杂度就已经超时了,这时要想办法去优化查询。

首先肯定要预处理出没有修改时当前员工在每年的排名情况,并且当前排名还要加上下一年招的人数,如果这个值大于n,那么这个人就会被踢出公司。

然后我们考虑修改的情况,如果将应聘的能力值低的人换成能力值高的人,那么1号员工在那一年起的排名都会增加1,反之会减少1,这里的区间加和区间减可以用线段树去维护,并且在查询时求一个区间最大值,如果大于n就不在公司里了。

Code

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
#define re register
#define fi first
#define se second
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
int a[N], num[N], now[N];
vector<int> ve[N], cp[N];
struct node {
    int l, r;
    int maxx, tag;
}t[N<<2];
void push_up(int u) {
    t[u].maxx = max(t[u<<1].maxx, t[u<<1|1].maxx);
}
void push_down(int u) {
    if (t[u].tag) {
        t[u<<1].tag += t[u].tag;
        t[u<<1|1].tag += t[u].tag;
        t[u<<1].maxx += t[u].tag;
        t[u<<1|1].maxx += t[u].tag;
        t[u].tag = 0;
    }
}
void build(int u, int l, int r) {
    t[u].l = l, t[u].r = r, t[u].tag = 0;
    if (l == r) {
        t[u].maxx = now[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(u<<1, l, mid);
    build(u<<1|1, mid+1, r);
    push_up(u);
}
void modify(int u, int ql, int qr, int val) {
    if (ql <= t[u].l && qr >= t[u].r) {
        t[u].maxx += val;
        t[u].tag += val;
        return;
    }
    push_down(u);
    int mid = (t[u].l + t[u].r) >> 1;
    if (ql <= mid) modify(u<<1, ql, qr, val);
    if (qr > mid) modify(u<<1|1, ql, qr, val);
    push_up(u);
}
int query(int u, int ql, int qr) {
    if (ql <= t[u].l && qr >= t[u].r) return t[u].maxx;
    push_down(u);
    int mid = (t[u].l + t[u].r) >> 1;
    int Max = 0;
    if (ql <= mid) Max = max(Max, query(u<<1, ql, qr));
    if (qr > mid) Max = max(Max, query(u<<1|1, ql, qr));
    return Max;
}
void solve() {
    int n, m, q; cin >> n >> m >> q;
    for (int i = 1; i <= n; i++) cin >> a[i];
    int val = a[1]; sort(a+1, a+n+1);
    now[1] = n - (lower_bound(a+1, a+n+1, val) - a - 1);
    for (int i = 1; i <= m; i++) {
        cin >> num[i];
        for (int j = 1; j <= num[i]; j++) {
            int x; cin >> x;
            ve[i].push_back(x);
            cp[i].push_back(x);
        }
        sort(cp[i].begin(), cp[i].end());
        now[i+1] = now[i] + num[i] - (lower_bound(cp[i].begin(), cp[i].end(), val) - cp[i].begin());
    }
    for (int i = 1; i <= m; i++) now[i] += num[i];
    build(1, 1, m);
    for (int i = 1; i <= q; i++) {
        int x, y, z; cin >> x >> y >> z;
        int dig = ve[x][y-1];
        int add = -(dig > val) + (z > val);
        if (x != m) modify(1, x+1, m, add);
        printf("%d\n", query(1, 1, m) > n ? 0 : 1);
        ve[x][y-1] = z;
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值