题解 序列

传送门

首先可以分块做
单调指针+桶排可以做到 \(O(n\sqrt n)\)

然后第一问可以用线段树维护

  • 关于一类标记合并线段树:
    当每种操作都形如「区间加上一个数」或「区间对一个数取max」时,可以在每个节点维护两个标记 \(tag1\)\(tag2\)
    若为叶子节点,则代表这个节点的实际权值应为 \(max(tag1, val_p)+tag2\)
    于是区间加 \(dat\) 等价于 \(tag2+=dat\)
    区间与 \(dat\) 取max等价于 \(tag1=max(tag1, dat-tag2)\)
    注意一个节点的标记下放的时候 \(tag1\) 要先下放
    容易看出复杂度是 \(O(nlogn)\)

第二问注意一个性质(开始复制题解):
考虑一个点所经过的所有操作序列
显然所有的add操作都对其产生了影响
将add操作合并,这样得到了一个操作序列 \(A_1,M_1,...,A_n,M_n\)
\(S_j=\sum\limits_{i\leqslant j} A_i\)
则在 \(M_i\) 操作后进行 \(M_j\) 操作的必要条件是 \(M_i + S_j −S_i <M_j\)
这说明所有进行的max操作是该点上 \(M_i −S_i\) 的一个递增序列
于是可以对每个点用线段树维护单调栈求出有多少个max操作修改了它的值
从一个点到下一个点对应了一些操作的插入与删除,可以用区间修改实现
于是在一棵支持区间修改的线段树上维护单调栈即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
#define pb push_back
//#define int long long

inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
char typ[10];
int op[N], l[N], r[N], c[N], a[N], ans2[N], sum[N], now;
ll bit[N], ans1[N];
vector<pair<int, int>> add[N], del[N];
vector<int> que[N];
inline void upd(int i, int val) {for (; i<=m; i+=i&-i) bit[i]+=val;}
inline ll query(int i) {ll ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
inline void upd2(int i, int val) {for (; i<=m; i+=i&-i) sum[i]+=val;}
inline ll query2(int i) {ll ans=0; for (; i; i-=i&-i) ans+=sum[i]; return ans;}
#define tl(p) tl[p]
#define tr(p) tr[p]
#define val(p) val[p]
#define tag(p) tag[p]
#define tag1(p) tag1[p]
#define tag2(p) tag2[p]
#define maxn(p) maxn[p]
#define rec(p) rec[p]
namespace seg1{
	int tl[N<<2], tr[N<<2];
	ll val[N<<2], tag1[N<<2], tag2[N<<2];
	inline void spread(int p) {
		tag1(p<<1)=max(tag1(p<<1), tag1(p)-tag2(p<<1)); tag2(p<<1)+=tag2(p);
		tag1(p<<1|1)=max(tag1(p<<1|1), tag1(p)-tag2(p<<1|1)); tag2(p<<1|1)+=tag2(p);
		tag1(p)=-INF; tag2(p)=0;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r; tag1(p)=-INF;
		if (l==r) {val(p)=a[l]; return ;}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void upd1(int p, int l, int r, ll dat) {
		if (l<=tl(p)&&r>=tr(p)) {tag1(p)=max(tag1(p), dat-tag2(p)); return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd1(p<<1, l, r, dat);
		if (r>mid) upd1(p<<1|1, l, r, dat);
	}
	void upd2(int p, int l, int r, ll dat) {
		if (l<=tl(p)&&r>=tr(p)) {tag2(p)+=dat; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd2(p<<1, l, r, dat);
		if (r>mid) upd2(p<<1|1, l, r, dat);
	}
	ll query(int p, int pos) {
		if (tl(p)==tr(p)) return max(tag1(p), val(p))+tag2(p);
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) return query(p<<1, pos);
		else return query(p<<1|1, pos);
	}
}

namespace seg2{
	int tl[N<<2], tr[N<<2], rec[N<<2];
	ll maxn[N<<2], tag[N<<2], nowmax;
	inline void spread(int p) {
		if (!tag(p)) return ;
		maxn(p<<1)+=tag(p); tag(p<<1)+=tag(p);
		maxn(p<<1|1)+=tag(p); tag(p<<1|1)+=tag(p);
		tag(p)=0;
	}
	int calc(int p, int val) {
		if (tl(p)==tr(p)) return maxn(p)>val?1:0;
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (val<=maxn(p<<1)) return calc(p<<1, val)+rec(p);
		else return calc(p<<1|1, val);
	}
	void pushup(int p) {
		maxn(p)=max(maxn(p<<1), maxn(p<<1|1));
		rec(p)=calc(p<<1|1, maxn(p<<1));
	}
	int query(int p, int l, int r) {
		// cout<<"query: "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<l<<' '<<r<<endl;
		if (p==1) nowmax=a[now];
		if (l<=tl(p)&&r>=tr(p)) {
			int t=calc(p, nowmax);
			nowmax=max(nowmax, maxn(p));
			return t;
		}
		spread(p);
		int mid=(tl(p)+tr(p))>>1, ans=0;
		if (l<=mid) ans+=query(p<<1, l, r);
		if (r>mid) ans+=query(p<<1|1, l, r);
		return ans;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r; maxn(p)=-INF;
		if (l==r) return ;
		int mid=(tl(p)+tr(p))>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void upd(int p, int pos, ll dat) {
		if (tl(p)==tr(p)) {maxn(p)=dat; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) upd(p<<1, pos, dat);
		else upd(p<<1|1, pos, dat);
		pushup(p);
	}
	void upd(int p, int l, int r, ll dat) {
		if (l<=tl(p)&&r>=tr(p)) {maxn(p)+=dat; tag(p)+=dat; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, dat);
		if (r>mid) upd(p<<1|1, l, r, dat);
		pushup(p);
	}
}

signed main()
{
	n=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	seg1::build(1, 1, n);
	m=read();
	seg2::build(1, 1, m);
	for (int i=1; i<=m; ++i) {
		scanf("%s", typ);
		if (*typ=='A') {
			op[i]=1; l[i]=read(); r[i]=read(); c[i]=read();
			if (!c[i]) continue;
			seg1::upd2(1, l[i], r[i], c[i]);
			add[l[i]].pb({i, 0});
			del[r[i]].pb({i, 0});
		}
		else if (*typ=='M') {
			op[i]=2; l[i]=read(); r[i]=read(); c[i]=read();
			seg1::upd1(1, l[i], r[i], c[i]);
			add[l[i]].pb({i, 1});
			del[r[i]].pb({i, 1});
		}
		else {
			op[i]=3; c[i]=read();
			que[c[i]].pb(i);
			ans1[i]=seg1::query(1, c[i]);
		}
	}
	for (int i=1; i<=n; ++i) {
		now=i;
		for (auto it:add[i])
			if (!it.sec) seg2::upd(1, it.fir, m, -c[it.fir]), upd(it.fir, c[it.fir]), upd2(it.fir, 1);
			else seg2::upd(1, it.fir, c[it.fir]-query(it.fir)); //, cout<<"upd: "<<it.fir<<' '<<c[it.fir]-query(it.fir)<<endl;
		for (auto it:que[i])
			ans2[it]=seg2::query(1, 1, it)+query2(it); //, cout<<"query2: "<<query2(it)<<endl;
		for (auto it:del[i])
			if (!it.sec) seg2::upd(1, it.fir, m, c[it.fir]), upd(it.fir, -c[it.fir]), upd2(it.fir, -1);
			else seg2::upd(1, it.fir, -INF);
	}
	for (int i=1; i<=m; ++i) if (op[i]==3) printf("%lld %d\n", ans1[i], ans2[i]);

	return 0;
}
posted @ 2021-12-23 21:44  Administrator-09  阅读(0)  评论(0编辑  收藏  举报