Codeforces Round #576 (Div. 2) D. Welfare State

题目链接

There is a country with n citizens. The i-th of them initially has ai money. The government strictly controls the wealth of its citizens. Whenever a citizen makes a purchase or earns some money, they must send a receipt to the social services mentioning the amount of money they currently have.

Sometimes the government makes payouts to the poor: all citizens who have strictly less money than x are paid accordingly so that after the payout they have exactly x money. In this case the citizens don’t send a receipt.

You know the initial wealth of every citizen and the log of all events: receipts and payouts. Restore the amount of money each citizen has after all events.

Input
The first line contains a single integer n (1≤n≤2⋅105) — the numer of citizens.

The next line contains n integers a1, a2, …, an (0≤ai≤109) — the initial balances of citizens.

The next line contains a single integer q (1≤q≤2⋅105) — the number of events.

Each of the next q lines contains a single event. The events are given in chronological order.

Each event is described as either 1 p x (1≤p≤n, 0≤x≤109), or 2 x (0≤x≤109). In the first case we have a receipt that the balance of the p-th person becomes equal to x. In the second case we have a payoff with parameter x.

Output
Print n integers — the balances of all citizens after all events.

Examples
inputCopy
4
1 2 3 4
3
2 3
1 2 2
2 1
outputCopy
3 2 3 4
inputCopy
5
3 50 2 1 10
3
1 2 0
2 8
1 3 20
outputCopy
8 8 20 8 10
Note
In the first example the balances change as follows: 1 2 3 4 → 3 3 3 4 → 3 2 3 4 → 3 2 3 4

In the second example the balances change as follows: 3 50 2 1 10 → 3 0 2 1 10 → 8 8 8 8 10 → 8 8 20 8 10

题意: 题意很简单,有一个长度为n的序列,两种操作,一个是单点更新,讲a[i]跟新为x。第二种操作,将1~n中,小于x的数全部跟新为x。
思路:
单点跟新就不用说了,这里主要说第二中操作。
维护区间min,如果说节点中的min需要跟新的话,那么就说明,当前区间中有值需要跟新,就需要一直递归。但是这种显然是会T掉的,所以还需要维护一个max。
如果该节点的max < x的话,那么整个区间就需要全部跟新,不需要再进行递归;如果该节点的min < x,则说明区间中有值需要跟新,则进入该节点;如果该节点最小值都不需要跟新的话,则区间不需要跟新。
总结反思: 线段树的代码量实在是太大了,这道题差不多写了半小时,最后优化,该BUG又是半小时,结果在比赛结束后10分钟左右才出来的吧,看来还是要学习一下树状数组的啊。后来问了大佬做法,听说是维护最大值和前缀最大值…懵逼,没听说过前缀最大值啊…

#include<bits/stdc++.h>
using namespace std;
#define lson (rt<<1)
#define rson ((rt<<1)|1)
const int MAXN = 210000;
struct node
{
    int x,y,layz;
}tree[MAXN<<2];

void pushup(int rt)
{
    tree[rt].x = max(tree[lson].x,tree[rson].x);
    tree[rt].y = min(tree[lson].y,tree[rson].y);
}

void build(int rt,int L,int R)
{
    if(L ==R){
        scanf("%d",&tree[rt].x);
        tree[rt].y = tree[rt].x;
        tree[rt].layz = 0;
        return ;
    }
    int Mid = (L+R)>>1;
    build(lson,L,Mid);
    build(rson,Mid+1,R);
    pushup(rt);
}

void pushdown(int rt)
{
    if(tree[rt].layz){
        tree[lson].layz = tree[rson].layz = tree[rt].layz;
        tree[lson].x = tree[rson].x = tree[rt].layz;
        tree[lson].y = tree[rson].y = tree[rt].layz;
        tree[rt].layz = 0;
        return ;
    }
}

void update(int rt,int L,int R,int x,int w)
{
    if(L==R){
        tree[rt].y = tree[rt].x = w;
        return ;
    }
    pushdown(rt);
    int Mid = (L+R)>>1;
    if(x <= Mid)    update(lson,L,Mid,x,w);
    else update(rson,Mid+1,R,x,w);
    pushup(rt);
}

void update1(int rt,int L,int R,int l,int r,int x)
{
    pushdown(rt);
    if(L==R)    return ;
    int Mid = (L+R)>>1;
    if(tree[lson].x <= x){
        tree[lson].x = tree[lson].y = tree[lson].layz = x;
    }
    else if(tree[lson].y < x)   update1(lson,L,Mid,l,r,x);
    if(tree[rson].x <= x){
        tree[rson].x = tree[rson].y = tree[rson].layz = x;
    }
    else if(tree[rson].y < x)   update1(rson,Mid+1,R,l,r,x);
    pushup(rt);
}

void query(int rt,int L,int R,int l,int r)
{
    if(L == R){
        printf("%d ",tree[rt].x);
        return ;
    }
    pushdown(rt);
    int Mid = (L+R)>>1;
    query(lson,L,Mid,l,r);
    query(rson,Mid+1,R,l,r);
}

int main()
{
    int n;
    scanf("%d",&n);
    build(1,1,n);
    int T;
    scanf("%d",&T);
    while(T--){
        int t;
        scanf("%d",&t);
        if(t == 1){
            int p,x;
            scanf("%d%d",&p,&x);
            update(1,1,n,p,x);
        }
        else{
            int x;
            scanf("%d",&x);
            if(tree[1].x <= x)  tree[1].x = tree[1].layz = x;
            else    update1(1,1,n,1,n,x);
        }
    }
    query(1,1,n,1,n);
    printf("\n");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值