Codeforces-1199D-Welfare State + HDU-4306-Gorgeous Sequence(线段树)

本文探讨了线段树在区间更新与查询中的应用,包括单点更新、区间更新及求最大值与和的复杂操作。通过Codeforces与HDU两道题目,详细解析了线段树的构建、更新及查询过程,展示了如何处理区间内的最大值、最小值及求和等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Codeforces-1199D-Welfare State:

There is a country with nn citizens. The ii-th of them initially has aiai 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 xx are paid accordingly so that after the payout they have exactly xx 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 nn (1≤n≤2⋅1051≤n≤2⋅105) — the numer of citizens.

The next line contains nn integers a1a1, a2a2, ..., anan (0≤ai≤1090≤ai≤109) — the initial balances of citizens.

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

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

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

Output

Print nn 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 

题意:1操作把p位置的值更改为x,2操作把整个序列中小于x的位置的值更改为x,输出最终的整个序列

题意分析:线段树题目,记录一个最小值,当我当前的最小值都要大于x的时候,那么我就不需要操作;否则,把当前更改的值lazytag标记下来,等之后的查询和1操作进行pushdown操作,把之前需要更改的值记录下来递归到子树中,在子树中碰到那些最小值大于当前的x的那么就直接return,有小于的就继续递归直到找到最终位置,这题目值得学习,加深了对线段树的理解和查询整个区间的方法

代码:

#include<bits/stdc++.h>
#define N 200005
using namespace std;
int n,m;
int a[N];
struct ljh
{
    int l,r,mn,lazy;
}e[4*N];
inline void makelazy(int node)
{
    if(e[node].lazy)
    {
        if(e[node<<1].mn<e[node].lazy)
        {
            e[node<<1].mn=e[node].lazy;
            e[node<<1].lazy=e[node].lazy;
        }
        if(e[node<<1|1].mn<e[node].lazy)
        {
            e[node<<1|1].mn=e[node].lazy;
            e[node<<1|1].lazy=e[node].lazy;
        }
    }
    e[node].lazy=0;
}
void Build(int node,int left,int right)
{
    e[node].l=left;
    e[node].r=right;
    e[node].lazy=0;
    if(left==right)
    {
        e[node].mn=a[left];
        return;
    }
    int m=(left+right)>>1;
    Build(node<<1,left,m);
    Build(node<<1|1,m+1,right);
    e[node].mn=min(e[node<<1].mn,e[node<<1|1].mn); 
}
void Update(int node,int pos,int y)
{
    if(e[node].l==pos&&e[node].r==pos)
    {
        // cout<<"ys\n";
        e[node].mn=y;
        // cout<<node<<" "<<e[node].mn<<endl;
        return;
    }
    makelazy(node);
    int m=(e[node].l+e[node].r)>>1;
    if(pos<=m)Update(node<<1,pos,y);
    else Update(node<<1|1,pos,y);
    e[node].mn=min(e[node<<1].mn,e[node<<1|1].mn);
}
void Update1(int node,int x)
{
    if(e[node].mn>=x)return;
    if(e[node].mn<x)
    {
        // cout<<node<<endl;
        e[node].lazy=x;
        e[node].mn=x;
        return;
    }
    /*makelazy(node);
    int m=(e[node].l+e[node].r)>>1;
    Update1(node<<1,x);
    Update1(node<<1|1,x);
    e[node].mn=min(e[node<<1].mn,e[node<<1|1].mn);*/
}
void Query(int node)
{
    if(e[node].l==e[node].r)
    {
        printf("%d ",e[node].mn);
        return;
    }
    makelazy(node);
    Query(node<<1);
    Query(node<<1|1);
    e[node].mn=min(e[node<<1].mn,e[node<<1|1].mn);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    Build(1,1,n);
    scanf("%d",&m);
    while(m--)
    {
        int op,x,y;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d",&x,&y);
            Update(1,x,y);
            // Query(1);
            // cout<<endl;
        }
        else
        {
            scanf("%d",&x);
            Update1(1,x);
            // Query(1);
            // cout<<endl;
        }
    }
    Query(1);
    return 0;
}

HDU-5306-Gorgeous Sequence

There is a sequence a of length n . We use ai to denote the i -th element in this sequence. You should do the following three types of operations to this sequence.
0 x y t : For every x≤i≤y , we use min(ai,t) to replace the original ai 's value.
1 x y : Print the maximum value of ai that x≤i≤y .
2 x y : Print the sum of ai that x≤i≤y .

Input

The first line of the input is a single integer T , indicating the number of testcases.
The first line contains two integers n and m denoting the length of the sequence and the number of operations.
The second line contains n separated integers a1,…,an (∀1≤i≤n,0≤ai<231 ).
Each of the following m lines represents one operation (1≤x≤y≤n,0≤t<231 ).
It is guaranteed that T=100 , ∑n≤1000000, ∑m≤1000000 .

Output

For every operation of type 1 or 2 , print one line containing the answer to the corresponding query.

Sample Input

1

5 5

1 2 3 4 5

1 1 5

2 1 5

0 3 5 3

1 1 5

2 1 5

Sample Output

5 15 3 12

 题意:跟上面的差不多,不过这里的是把所有区间改成了从x到y内,所以大于z的就改为z,查询x到y最大值,再求x到y的和

题意分析:这个题目我最开始稍微改一下就好了,后面发现求sum是一个麻烦,因为更改最大值,只需要在父节点树中更改,但是求和不好怎么更改啊。。。必须要递归到子树,后来想,如果我在更改时加上一个最小值,当最小值也大于等于z时,那么他的子树的sum就直接全部更改为(r-l+1)*z了,顺利过了样例,交上去WA了,后来实在不会,看了这篇博客,因为临近省赛选拔也就没有自己再写了,理解了一下求法,在最大值的基础上加上最大值的个数,跟次大值的数,碰到当 次大值<z<最大值 时只需要对最大值进行更改,sum+=最大值个数*最大值就好了,然后把最大值当成lazytag标记,每次都是求取的最大值的sum在慢慢递归下去,进行剪枝

AC代码:

#include<cstdio>
#include<iostream>
#define lc k<<1
#define rc k<<1|1
#define EF if(ch==EOF) return x;
using namespace std;
typedef long long ll;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;EF;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int N=1e6+5;
const int M=N<<2;
int n,m,a[N];
ll sum[M];int mx[M],se[M],mc[M];
//最大值,次大值,最大值个数
inline void updata(int k){
    sum[k]=sum[lc]+sum[rc];
    mx[k]=max(mx[lc],mx[rc]);//最大值
    se[k]=max(se[lc],se[rc]);//次大值
    mc[k]=0;//最大值个数
    if(mx[lc]!=mx[rc]) 
        se[k]=max(se[k],min(mx[lc],mx[rc]));//选择次大值
    if(mx[k]==mx[lc]) mc[k]+=mc[lc];
    //如果左边有最大值,那么加上左边最大值的个数
    if(mx[k]==mx[rc]) mc[k]+=mc[rc];
    //如果右边有最大值,加上右边最大值个数
}
inline void dec_tag(int k,int v){
    if(v>=mx[k]) return ;
    sum[k]+=1LL*(v-mx[k])*mc[k];
    mx[k]=v;
}
inline void pushdown(int k){
    dec_tag(lc,mx[k]);
    //采用最大值来更新,其实最大值也就可以相当于是lazytag标记,其实就是每次对最大值的那些地方进行更改,但是我个人甚至认为会T
    dec_tag(rc,mx[k]);
}

void build(int k,int l,int r){
    if(l==r){
        sum[k]=mx[k]=a[l];
        mc[k]=1;
        se[k]=-1;
        return ;
    }
    int mid=(l+r)>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    updata(k);
}

void change(int k,int l,int r,int x,int y,int v){
    if(v>=mx[k]) return ;
    if(l==x&&r==y&&v>se[k]){
        dec_tag(k,v);return ;//只需要更改最大值
    }
    pushdown(k);
    int mid=(l+r)>>1;
    if(y<=mid) change(lc,l,mid,x,y,v);
    else if(x>mid) change(rc,mid+1,r,x,y,v);
    else change(lc,l,mid,x,mid,v),change(rc,mid+1,r,mid+1,y,v);
    updata(k);    
}

int query_max(int k,int l,int r,int x,int y){
    if(l>=x&&r<=y) return mx[k];
    pushdown(k);
    int mid=l+r>>1;
    if(y<=mid) return query_max(lc,l,mid,x,y);
    else if(x>mid) return query_max(rc,mid+1,r,x,y);
    else return max(query_max(lc,l,mid,x,mid),query_max(rc,mid+1,r,mid+1,y));
}
ll query_sum(int k,int l,int r,int x,int y){
    if(l==x&&r==y) return sum[k];
    pushdown(k);
    int mid=l+r>>1;
    if(y<=mid) return query_sum(lc,l,mid,x,y);
    else if(x>mid) return query_sum(rc,mid+1,r,x,y);
    else return query_sum(lc,l,mid,x,mid)+query_sum(rc,mid+1,r,mid+1,y);
}
inline void work(){
    n=read();m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    build(1,1,n);
    for(int i=1,opt,x,y,z;i<=m;i++){
        opt=read();x=read();y=read();
        if(opt==0) z=read(),change(1,1,n,x,y,z);
        if(opt==1) printf("%d\n",query_max(1,1,n,x,y));
        if(opt==2) printf("%lld\n",query_sum(1,1,n,x,y));
    }
}
int main(){
    for(int T=read();T--;) work();
    return 0;
}

TLE代码:

#include<bits/stdc++.h>
#define N 1000005
#define LL long long
using namespace std;
int t,n,m;
LL a[N],ans;
struct ljh
{
	int l,r;
	LL lazy,sum,mx,mn;
}e[N*4];
inline void make(int node)
{
	e[node].sum=e[node<<1].sum+e[node<<1|1].sum;
	e[node].mx=max(e[node<<1].mx,e[node<<1|1].mx);
	e[node].mn=min(e[node<<1].mn,e[node<<1|1].mn);
}
inline void makelazy(int node)
{
	if(e[node].lazy)
	{
		if(e[node<<1].mx>e[node].lazy)
		{
			e[node<<1].lazy=e[node].lazy;
			e[node<<1].mx=e[node].lazy;
		}
		if(e[node<<1].mn>e[node].lazy)
		{
			e[node].mn=e[node].lazy;
		}
		if(e[node<<1|1].mx>e[node].lazy)
		{
			e[node<<1|1].lazy=e[node].lazy;
			e[node<<1|1].mx=e[node].lazy;
		}
		if(e[node<<1|1].mn>e[node].lazy)
		{
			e[node<<1|1].mn=e[node].lazy;
		}
		e[node].lazy=0;
	}
}
void Build(int node,int left,int right)
{
	e[node].l=left;
	e[node].r=right;
	e[node].lazy=0;
	if(left==right)
	{
		e[node].mn=a[left];
		e[node].mx=a[left];
		e[node].sum=a[left];
		return;
	}
	makelazy(node);
	int m=(left+right)>>1;
	Build(node<<1,left,m);
	Build(node<<1|1,m+1,right);
	make(node);
}
void Update(int node,int x,int y,LL z)
{
	if(e[node].mx<=z)return;
	if(x<=e[node].l&&e[node].r<=y&&e[node].mn>=z)
	{
		e[node].lazy=z;
		e[node].mx=z;
		e[node].mn=z;
		e[node].sum=(e[node].r-e[node].l+1)*z;
		return;
	}
	makelazy(node);
	int m=(e[node].l+e[node].r)>>1;
	if(x<=m)Update(node<<1,x,y,z);
	if(y>m)Update(node<<1|1,x,y,z);
	make(node);
}
LL Querymax(int node,int x,int y)
{
	LL Max=0;
	if(x<=e[node].l&&e[node].r<=y)
	{
		return e[node].mx;
	}
	makelazy(node);
	int m=(e[node].l+e[node].r)>>1;
	if(x<=m)
	Max=max(Max,Querymax(node<<1,x,y));
	if(y>m)
	Max=max(Max,Querymax(node<<1|1,x,y));
	return Max;
}
void Querysum(int node,int x,int y)
{
	if(x<=e[node].l&&e[node].r<=y)
	{
		ans+=e[node].sum;
		return;
	}
	makelazy(node);
	int m=(e[node].l+e[node].r)>>1;
	if(m>=x)Querysum(node<<1,x,y);
	if(m<y)Querysum(node<<1|1,x,y);
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
		Build(1,1,n);
		while(m--)
		{
			int op,x,y;
			LL z;
			scanf("%d",&op);
			if(op==0)
			{
				scanf("%d%d%lld",&x,&y,&z);
				Update(1,x,y,z);
			}
			if(op==1)
			{
				scanf("%d%d",&x,&y);
				printf("%lld\n",Querymax(1,x,y));
			}
			if(op==2)
			{
				ans=0;
				scanf("%d%d",&x,&y);
				Querysum(1,x,y);
				printf("%lld\n",ans);
			}
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值