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. Input The first line of the input is a single integer T , indicating the number of testcases. 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);
}
}
}
}