ABC342
G
总之纪念一下赛时G。
经典标记永久化,可惜我之前不会标记永久化,于是在赛时自己推导了(发明了)一种算法,赛后才知道是标记永久化。
建一棵线段树,考虑没有撤销操作的情况。
显然,一次操作代表一个区间所有数不能小于 \(x\),于是我们将线段树上包含在区间内的节点标记上 \(x\),如果之前已经有标记,就与之前标记取较大值。
查询时由于是单点查询,可以将路径上的标记取最大值与 \(A_i\) 比较即为答案。
正确性显然。
考虑撤销操作。本质上就是废除一次标记。
于是我们考虑将每个节点的历史标记记录下来,撤销时删除这次历史即可,用 multiset 可以方便维护历史标记最大值。
由于每次修改操作只会改变 \(\log\) 个节点,于是一次撤销也只对这 \(\log\) 个节点操作,时间复杂度 \(O(q\log^2 n)\),可能常数略大。
#include<bits/stdc++.h>
#define int long long
template<typename T>
void read(T &x){
int f=1;
char c=getchar();
x=0;
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
template<typename T,typename I>
void chkmin(T &a,I b){
a=std::min(a,b);
}
template<typename T,typename I>
void chkmax(T &a,I b){
a=std::max(a,b);
}
const int inf=1e18+10,MOD1=998244353,MOD2=1e9+7;
const int maxn=2e5+10;
int a[maxn];
struct node{
int l,r,ls,rs;
std::multiset<int>st;
}s[maxn*2];
struct op{
int k,x;
};
std::vector<op>po[maxn];
int tot=0,cnt=0;
int build(int l,int r){
int p=++tot;
s[p].l=l,s[p].r=r;
s[p].st.insert(-inf);
if(l==r) return p;
int mid=(l+r)>>1;
s[p].ls=build(l,mid);
s[p].rs=build(mid+1,r);
return p;
}
void update(int k,int p,int L,int R,int x){
int l=s[p].l,r=s[p].r;
if(l>=L&&r<=R){
s[p].st.insert(x);
op nowop;
nowop.k=p,nowop.x=x;
po[k].push_back(nowop);
return ;
}
int mid=(l+r)>>1;
if(mid>=L) update(k,s[p].ls,L,R,x);
if(R>mid) update(k,s[p].rs,L,R,x);
return ;
}
void del(int k){
//撤销第 k 次插入操作
for(auto q:po[k]){
s[q.k].st.erase(s[q.k].st.find(q.x));
}
}
int query(int p,int k){
int l=s[p].l,r=s[p].r;
auto z=s[p].st.end();
z--;
int ret=*z;
if(l==r) return ret;
int mid=(l+r)>>1;
if(k<=mid) chkmax(ret,query(s[p].ls,k));
else chkmax(ret,query(s[p].rs,k));
return ret;
}
int t[maxn];//t[i] 代表第 i 次操作是第几次插入操作
signed main(){
int n;
read(n);
for(int i=1;i<=n;i++) read(a[i]);
build(1,n);
int q;
read(q);
int tim=0;
while(q--){
tim++;
int opt;
read(opt);
if(opt==1){
int l,r,x;
read(l),read(r),read(x);
cnt++;
t[tim]=cnt;
update(cnt,1,l,r,x);
}else if(opt==2){
int i;
read(i);
del(t[i]);
}else{
int i;
read(i);
printf("%lld\n",std::max(query(1,i),a[i]));
}
}
return 0;
}
/*
-读入字符一定检查回车
- 能不能搜索?
-函数要有返回值!
-想好了再写!
*/