Codeforces Round #576 (Div. 2) D (线段树+lazy-tag & 模拟)

本文介绍了Codeforces Round #576 (Div. 2) D题目的解决方案,该题目涉及线段树和懒惰标记的概念。题目要求根据初始财富和一系列事件(包括单点更新和全局更新),恢复每个公民最终的财富状况。通过线段树配合懒惰标记,或者通过记录每个位置的更新最大值,可以有效地解决这个问题。
摘要由CSDN通过智能技术生成

D. Welfare State
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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个数 有两种操作
1.将第 i个数变为 b
2.将低于b的数变为b
输出m次操作后的 这n个数分别是多少。

有两种做法:
方法一: 很容易看出可以使用线段树来做,1操作是单点更新,2操作设置lazy-tag当要对区间进行变化的时候再进行更新。

#include<bits/stdc++.h>
using namespace std;
const int N = 500500;
struct Tree
{
	int tag,value;
};
Tree t[N<<2];
int a[N];
void Update(int rt)
{
	t[rt].value = max(t[rt<<1].value,t[rt<<1|1].value);
}
void build(int l,int r,int rt)
{
	t[rt].tag=0;
	if(l==r)
	{
		t[rt].value = a[l];
		return;
	}
	
	build(l,(l+r)>>1,rt<<1);
	build((l+r)>>1|1,r,rt<<1|1);
	Update(rt);
}

void Update2(int rt)
{
	if(t[rt].tag)
	{
		int add = t[rt].tag;
		t[rt<<1].tag = max(t[rt<<1].tag,add);
		t[rt<<1|1].tag = max(t[rt<<1|1].tag,add);
		t[rt].tag = 0;
	}
}


void change(int p,int add,int l,int r,int rt)
{
	if(l==r)
	{
		t[rt].value = add;
		return;
	}
	
	Update2(rt);
	int mid = (l+r)>>1;
	if(p<=mid)
	change(p,add,l,mid,rt<<1);
	else
	change(p,add,mid+1,r,rt<<1|1);
	Update(rt);
}

int query(int p,int l,int r,int rt)
{
	if(l==r)
	{
		return t[rt].value;
	}
	
	Update2(rt);
	int mid = (l+r)>>1;
	if(p<=mid)
	query(p,l,mid,rt<<1);
	else
	query(p,mid+1,r,rt<<1|1);
	Update(rt);
}

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	build(1,n,1);
	int m;
	scanf("%d",&m);
	for(int i=0;i<m;i++)
	{
		int q;
		scanf("%d",&q);
		if(q==1)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			change(a,b,1,n,1);
		}
		else
		{
			int a;
			scanf("%d",&a);
			t[1].tag = max(t[1].tag,a);
			t[1].value = max(t[1].value,a);
		}
	}
	
	for(int i=1;i<=n;i++)
	{
		printf("%d",query(i,1,n,1));
		if(i==n)
		printf("\n");
		else
		printf(" ");
	} 
	
}

方法二: 因为操作2是会被后到操作1或者是比它大的操作2所覆盖的,因此可以将所有进行过操作1的位置标记出来,然后逆序找出每个位置操作2所得到的最大值,比较它们取最大值。

 #include<bits/stdc++.h>
 using namespace std;
 #define N 500000
 int peo[N];
 int vis[N];
 int change[N];
 int main()
 {
 	int n;
 	scanf("%d",&n);
 	memset(vis,-1,sizeof(vis));
 	memset(change,-1,sizeof(change));
 	for(int i=0;i<n;i++)
 	scanf("%d",&peo[i]);
 	
 	int m;
 	scanf("%d",&m);
 	for(int i=0;i<m;i++)
 	{
		int q;
		scanf("%d",&q);
		if(q==1)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			peo[a-1]=b;
			vis[a-1]=i;
		}
		else
		{
			int a;
			scanf("%d",&a);
			change[i]=a;
		}
	}
	
	int maxx = -1;
	for(int i=m-1;i>=0;i--)
	{
		change[i] = max(maxx,change[i]);
		maxx = change[i];
	}
	
	for(int i=0;i<n;i++)
	{
		if(vis[i]==-1)
		printf("%d",max(peo[i],change[0]));
		else
		printf("%d",max(peo[i],change[vis[i]]));
		if(i==n-1)
		printf("\n");
		else
		printf(" ");
	}
	
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值