题目链接:https://vjudge.net/problem/CodeForces-1198B
思维版本转自:https://blog.csdn.net/qq_41949535/article/details/98657294
题意:有一些数字,以及一些操作。操作一是单点修改,输入1 b c,将位置b改成c,操作二是输入2 a,将不大于a的数全部改成a。求更改完毕后的数。
思路:暴力超时。可以发现有一些规律:一个数的值只与它最后的单点修改的值以及其以后的区间修改的最大值有关。详见注释。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int a[maxn],b[maxn],d[maxn];//初始金钱 单点修改的时间 区间修改值
int main()
{
int n;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
}
int q;
scanf("%d",&q);
for(int i=0; i<q; i++)
{
int x;
scanf("%d",&x);
if(x==1)
{
int e,f;
scanf("%d%d",&e,&f);
b[e-1]=i;//记录最后一次单点修改的时间
a[e-1]=f;//直接更改掉原值
}
else
{
int e;
scanf("%d",&e);
d[i]=e;//记录区间修改的值
}
}
for(int i=q-1; i>=0; i--)//按照时间顺序的倒序从后往前递推区间修改的最大值
{
d[i]=max(d[i],d[i+1]);
}
for(int i=0; i<n; i++)//计算答案 因为数的值只与最后一次单点修改与其以后的区间修改的最大值有关
{
a[i]=max(a[i],d[b[i]]);
}
for(int i=0; i<n; i++)
{
if(i)
printf(" ");
printf("%d",a[i]);
}
return 0;
}
线段树版本转自:https://blog.csdn.net/weixin_40788897/article/details/98029557
思路:value维护最小值,区间更新时如果要更新的值小于区间最小值,那么就可以不更新,否则更新。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e5+5;
struct node
{
int l, r;
int value;
int lazy;
node()
{
l = r = value = lazy = 0;
}
} T[maxn<<2];
void Push_Down(int cur)
{
int lazy = T[cur].lazy;
T[cur].lazy = 0;
T[cur<<1].value > lazy ? T[cur<<1].value : (T[cur<<1].lazy = lazy, T[cur<<1].value = lazy);
T[cur<<1|1].value > lazy ? T[cur<<1|1].value : (T[cur<<1|1].lazy = lazy, T[cur<<1|1].value = lazy);
}
void build(int l, int r, int cur)
{
T[cur].l = l;
T[cur].r = r;
if(l == r)
{
scanf("%d", &T[cur].value);
return ;
}
int mid = (l+r)>>1;
build(l, mid, cur<<1);
build(mid+1, r, cur<<1|1);
T[cur].value = min(T[cur<<1].value, T[cur<<1|1].value);
}
void Update_Seg(int l, int r, int _left, int _right, int cur, int val)
{
if(_left <= l && r <= _right)
{
if(T[cur].value >= val)
return ;
T[cur].value = val;
T[cur].lazy = val;
return ;
}
Push_Down(cur);
int mid = (l+r)>>1;
if(_right <= mid)
Update_Seg(l, mid, _left, _right, cur<<1, val);
else if(_left > mid)
Update_Seg(mid+1, r, _left, _right, cur<<1|1, val);
T[cur].value = min(T[cur<<1].value, T[cur<<1|1].value);
}
void Update_Point(int l, int r, int pos, int cur, int val)
{
if(l == r)
{
T[cur].value = val;
return ;
}
Push_Down(cur);
int mid = (l+r)>>1;
if(pos <= mid)
Update_Point(l, mid, pos, cur<<1, val);
else
Update_Point(mid+1, r, pos, cur<<1|1, val);
T[cur].value = min(T[cur<<1].value, T[cur<<1|1].value);
}
int Get(int l, int r, int pos, int cur)
{
if(l == r)
return T[cur].value;
int mid = (l+r)>>1;
Push_Down(cur);
if(pos <= mid)
return Get(l, mid, pos, cur<<1);
else
return Get(mid+1, r, pos, cur<<1|1);
}
int main()
{
int n, q;
cin >> n;
build(1, n, 1);
cin >> q;
while(q--)
{
int op, x, p;
scanf("%d", &op);
if(op == 1)
{
scanf("%d%d", &p, &x);
Update_Point(1, n, p, 1, x);
}
else
{
scanf("%d", &x);
Update_Seg(1, n, 1, n, 1, x);
}
}
for(int i = 1; i <= n; i++)
{
if(i == 1)
printf("%d", Get(1, n, i, 1));
else
printf(" %d", Get(1, n, i, 1));
}
cout << endl;
return 0;
}