Codeforces[1199D] Welfare State 【线段树单点修改+区间更新】

Description

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\leq n\leq 2\cdot 10^5)— the numer of citizens.

The next line contains n integers a_1,a_2,...,a_n (0\leq a_i\leq 10^9) — the initial balances of citizens.

The next line contains a single integer q (1\leq q\leq 2\cdot 10^5) — 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\leq q\leq n,0\leq x\leq 10^9), or 2 x (0\leq x\leq 10^9). In the first case we have a receipt that the balance of the pp -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 

input

4
1 2 3 4
3
2 3
1 2 2
2 1

output

3 2 3 4  

input

 5
3 50 2 1 10
3
1 2 0
2 8
1 3 20

output 

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

题目大意:

有一串数据,对这串数据可进行以下两种操作:

1、更改任意位置的数据; 

2、给定一个数据,将序列中所有小于这个数的数据都改为这个数。

要求给出q次操作后的序列。

分析:

由于线段树支持单点修改和区间更新,这题可用线段树解决。

每个区间维护该区间的最小值,延迟标记 tag 记录待更改的区间最小值(即操作2中给定的值)。若子区间的最小值大于 tag ,则不需下推(该区间不需更新),否则下推更新。

操作1则是正常的线段树单点修改。

最后查询每个叶子节点的值就是答案。这里必须依次查询,保证每个延迟标记都被下推到叶子节点。

具体解释见代码。

#include <iostream>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <string>

#include <vector>

#include <set>

#include <cstdio> 

#include <map> 

#include <iomanip>

 
#define rep(i,a,b) for(int i=a;i<=b;i++)

#define ll long long

#define INF 0x3f3f3f3f

 
using namespace std;

ll a[200005]; 

struct segtree{

	int l,r;

	ll minn; 

	int tag;//延迟标记 

};

 

segtree t[200005*4];

void pushup(int p){//上推,维护区间最小值 

	int lson=p*2,rson=p*2+1;

	t[p].minn=min(t[lson].minn,t[rson].minn);

} 

void pushdown(int p){//将父节点的状态向下传递(延迟标记的传递) 

	if(t[p].tag!=-1){//说明父节点的状态已被改变 

		int lson=p*2,rson=p*2+1;
		
		//子节点的tag小于父节点或者子节点未被更新,需要下推,另外下推后要用子节点的tag更新子节点区间的最小值 
		if(t[lson].tag<t[p].tag||t[lson].tag==-1)  t[lson].tag=t[p].tag;
		if(t[lson].minn<t[lson].tag)  t[lson].minn=t[lson].tag;
		 
		if(t[rson].tag<t[p].tag||t[rson].tag==-1)  t[rson].tag=t[p].tag;
		if(t[rson].minn<t[rson].tag)  t[rson].minn=t[rson].tag;

		t[p].tag=-1;//父节点传递完成后标志复原 

	}

}

void build(int p,int l,int r){//建树 

	int mid=(l+r)/2;

	t[p].l=l;

	t[p].r=r;

	t[p].tag=-1;

	if(l==r){
		
		t[p].minn=a[l];
		
		return;
	}

	build(p*2,l,mid);

	build(2*p+1,mid+1,r);
	
	pushup(p);

}
 
//查询叶子节点的值 
ll query(int index,int p){

	if(t[p].l==t[p].r){

		return t[p].minn;

	}

	pushdown(p);//首先将本节点的状态传递下去,便于接下来的递归查询 

	int lson=p*2;

	int rson=p*2+1;
	
	int mid=(t[p].l+t[p].r)/2;

	if(index<=mid)  return query(index,lson);
	
	else  return query(index,rson);

} 

//单点修改 
void change(int p,int index,ll num){
	
	if(t[p].l==t[p].r){
		
		t[p].minn=num;
		
		t[p].tag=-1;
		
		return;
	}
	
	int mid=(t[p].l+t[p].r)/2;
	
	pushdown(p);//修改前要先下推 
	
	if(index<=mid){
		
		change(p*2,index,num);
		
	}
	else{
		
		change(p*2+1,index,num);
		
	}
	
	pushup(p);//修改完成后要上推 
}
 
//区间更新 
void update(int p,int L,int R,ll x){ 

	int lson=p*2,rson=p*2+1;

	if(L<=t[p].l&&R>=t[p].r){//区间被完全覆盖 

		if(t[p].minn<x){
			
			t[p].tag=x;//这里区间的tag被更新为要求的值 
			
			t[p].minn=x;
			
		}

		return;//由于此处直接返回,所以需要延迟标记,此处未更新该节点的子树 

	}

	pushdown(p);//进入子节点前先传递延迟标记,便于接下来的递归更新 

	int mid=(t[p].l+t[p].r)/2;

	if(L<=mid){

		update(lson,L,R,x);

	} 

	if(R>mid){

		update(rson,L,R,x);

	}

	pushup(p);//子节点更新返回后要更新父节点 

}

 
int main(){

	int n,q;

	scanf("%d",&n);
	
	rep(i,1,n){
		
		scanf("%I64d",&a[i]);
	}

	build(1,1,n);
	
	scanf("%d",&q);

	rep(i,1,q){

		int com;

		scanf("%d",&com);

		if(com==1){

			int p;
			
			ll x;

			scanf("%d%I64d",&p,&x);

			change(1,p,x);

		}

		else{

			ll x;

			scanf("%I64d",&x); 

			update(1,1,n,x);

		}

	} 
	
	rep(i,1,n){
		
		printf("%I64d%c",query(i,1),(i==n?'\n':' '));
	}

	return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值