CodeForces - 1252G Performance Review(线段树)
题目大意
给出n个人,每个人都有一个能力值。然后公司每年会把能力值最低的几个人换掉,然后还有q个修改方案,修改方案会修改之前替换的能力值,问原来n个人中的第一个人是否会被t掉。
解题思路
首先需要统计出未修改时上次替换之后还有多少人的能力值比第一个人小,然后将其与现在需要替换的人数相减,如果值小于0的话,那么第一个人就会被裁掉(这里的负数是有意义的,这个负数代表了之前必须有多少个原来比第一个人能力值变的比他小才能使第一个人不会被裁掉,注意到这点的话这题基本就能解出来了)。然后对于每次修改,如果修改的这个值比第一个人的能力值大(小),而修改前比他小(大),那么修改以后的年份都会受影响,修改之后判断一下是否出现负数就行了。可以用线段树来维护这个过程。
代码
const int maxn = 1e5+10;
const int maxm = 2e5+10;
int a[maxn], les[maxn];
vector<int> b[maxn];
struct N {
int minn, lz;
} tree[maxn<<2];
inline void push_up(int rt) {
tree[rt].minn = min(tree[rt<<1].minn, tree[rt<<1|1].minn);
}
inline void push_down(int rt) {
if (tree[rt].lz) {
int lz = tree[rt].lz;
N &ls = tree[rt<<1];
N &rs = tree[rt<<1|1];
ls.lz += lz, rs.lz += lz;
ls.minn += lz, rs.minn += lz;
tree[rt].lz = 0;
}
}
void build(int rt, int l, int r) {
if (l==r) {
tree[rt].minn = les[l];
return;
}
int mid = (l+r)>>1;
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
push_up(rt);
}
void update(int rt, int l, int r, int a, int b, int val) {
if (l>=a && r<=b) {
tree[rt].lz += val;
tree[rt].minn += val;
return;
}
push_down(rt);
int mid = (l+r)>>1;
if (a<=mid) update(rt<<1, l, mid, a, b, val);
if (b>mid) update(rt<<1|1, mid+1, r, a, b, val);
push_up(rt);
}
int main() {
int n, m, q; cin >> n >> m >> q;
for (int i = 1; i<=n; ++i) scanf("%d", &a[i]);
for (int i = 1, k; i<=m; ++i) {
scanf("%d", &k); b[i].push_back(0);
for (int j = 1, num; j<=k; ++j) {
scanf("%d", &num);
b[i].push_back(num);
}
}
int x, y, z;
for (int i = 2; i<=n; ++i)
if (a[i]<a[1]) ++les[0];
les[1] = les[0];
for (int i = 1; i<=m; ++i) {
les[i+1] = les[i];
les[i] -= b[i].size()-1;
for (int j = 1; j<b[i].size(); ++j)
if (b[i][j]>a[1]) --les[i+1];
//cout << les[i] << endl;
}
build(1, 1, m);
while(q--) {
scanf("%d%d%d", &x, &y, &z);
if (x!=m && b[x][y]>a[1] && z<a[1]) update(1, 1, m, x+1, m, 1);
else if (x!=m && b[x][y]<a[1] && z>a[1]) update(1, 1, m, x+1, m, -1);
b[x][y] = z;
printf("%d\n", tree[1].minn>=0);
}
return 0;
}