CF 292E 题解

题目传送门

提供一个比较简单的做法。

对于每一次覆盖,不用线段树直接去存两端点 \([l,r]\),可以存下来这次修改对应第几次覆盖(未被覆盖为 \(0\)),查找时再根据存储的次数去输出。

最后输出时如果未被覆盖,直接输出 \(b[i]\),如果有覆盖次数 \(num\),则对应数组 \(A\) 的下标为:(\(X\)\(Y\) 为对应 \(A\)\(B\) 该次覆盖的下标)

\[(i-x[num]+1)+y[num]-1=i-x[num]+y[num] \]

时间复杂度 \(O(m\log{n})\),可以通过本题。

#include <iostream>
#include <cstdio>
#define SIZE 131072
#define ll long long

using namespace std;
int x[100005], y[100005], w[SIZE*2+5], tag[SIZE*2+5], cnt, n, m, a[100005], b[100005];
//线段树
void build(ll p, ll l, ll r){
	tag[p]=0;
	if(l==r){
		w[p]=0;
		return;
	}
	int mid=(l+r)>>1;
	build(p*2, l, mid);
	build(p*2+1, mid+1, r);
	w[p]=w[p*2]+w[p*2+1];
}
void f(ll p, ll l, ll r, ll k){
//下推的时候注意,如果k=0(没有)就不要往下放,要不然会覆盖掉原有的标记(被卡了好久)
	if(k!=0) tag[p]=k;
	if(k!=0) w[p]=(r-l+1)*k;
}
void update(ll p, ll nl, ll nr, ll l, ll r, ll k){
	if(nl<=l&&nr>=r){
		tag[p]=k;
		w[p]=(r-l+1)*k;
		return;
	}
	ll mid=(l+r)>>1;
	f(p*2, l, mid, tag[p]);
	f(p*2+1, mid+1, r, tag[p]);
	tag[p]=0;
	if(nl<=mid) update(p*2, nl, nr, l, mid, k);
	if(nr>mid) update(p*2+1, nl, nr, mid+1, r, k);
	w[p]=w[p*2]+w[p*2+1];
}
ll query(ll p, ll nl, ll nr, ll l, ll r){
	ll res=0;
	if(nl<=l&&nr>=r) return w[p];
	//下放到下面一层
	ll mid=(l+r)>>1;
	f(2*p, l, mid, tag[p]);
	f(2*p+1, mid+1, r, tag[p]);
	tag[p]=0;
	if(nl<=mid) res+=query(2*p, nl, nr, l, mid);
	if(nr>mid) res+=query(2*p+1, nl, nr, mid+1, r);
	return res;
}
int main(){
    scanf("%d%d", &n, &m);
    for (int i=1; i<=n; i++) scanf("%d", &b[i]);
    for (int i=1; i<=n; i++) scanf("%d", &a[i]);
    build(1, 1, n);
    while (m--){
        long long cmd;
        scanf("%lld", &cmd);
        if(cmd==1){
        	ll z;++cnt;
        	scanf("%d%d%lld", &y[cnt], &x[cnt], &z);
           	//更新时范围是从起点到起点+z-1(输入时数组写反了)
			update(1, x[cnt], x[cnt]+z-1, 1, n, cnt); 
		}
		else{
			int u;scanf("%d", &u);
			ll num=query(1, u, u, 1, n);
        		//分情况输出
			if(num) printf("%d\n", b[u-x[num]+y[num]]);
			else printf("%d\n", a[u]);
		}
    }
    return 0;//完结撒花
}
posted @ 2024-02-06 21:21  Network_Flow  阅读(32)  评论(0)    收藏  举报