题解 b

传送门

  • 一个随机序列的最长上升子序列长度期望是 \(O(\sqrt n)\) 级别的

那么对询问(不是操作)按 \(l\) 排序后期望形成 \(O(\sqrt n)\) 个 询问均呈包含关系的集合
对每个集合分别吉司机线段树暴力求答案
这样复杂度就是 \(O(n\sqrt q[\log n, log^2 n])\)

然后这个东西会 T 飞
我们重新审视一遍题面
\(n, m=15000, q=1e5\)
时限是 4s 有 O2,那么 \(O(nq)\) 是可以过的
于是将所有修改按权值从小到大排序,做区间覆盖即可
做区间覆盖需要一个额外的复杂度,精细实现可以跑的很快
什么你说你能卡掉?那么把这道题当做 Ynoi 就可以指令集优化了

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

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
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;
}

int n, m, q;
int a[N], tl[N], tr[N], x[N];

namespace force{
	int b[N];
	void solve() {
		for (int i=1,l,r,ql,qr; i<=q; ++i) {
			l=read(); r=read(); ql=read(); qr=read();
			for (int j=1; j<=n; ++j) b[j]=a[j];
			for (int j=l; j<=r; ++j)
				for (int k=tl[j]; k<=tr[j]; ++k)
					b[k]=min(b[k], x[j]);
			ll sum=0;
			for (int j=ql; j<=qr; ++j) sum+=b[j];
			printf("%lld\n", sum);
		}
	}
}

namespace task1{
	int b[N];
	multiset<int> s;
	vector<int> add[N], del[N];
	void solve() {
		for (int i=1,l,r,ql,qr; i<=q; ++i) {
			l=read(); r=read(); ql=read(); qr=read();
			for (int j=1; j<=n; ++j) b[j]=a[j], s.clear(), add[j].clear(), del[j].clear();
			for (int j=l; j<=r; ++j) {
				add[tl[j]].pb(x[j]);
				del[tr[j]].pb(x[j]);
			}
			for (int j=1; j<=n; ++j) {
				for (auto& it:add[j]) s.insert(it);
				if (s.size()) b[j]=min(b[j], *s.begin());
				for (auto& it:del[j]) s.erase(s.find(it));
			}
			ll sum=0;
			for (int j=ql; j<=qr; ++j) sum+=b[j];
			printf("%lld\n", sum);
		}
	}
}

namespace task{
	ll ans;
	int top;
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	int tl[15010<<2], tr[15010<<2], len[15010<<2], sum[15010<<2];
	struct que{int l, r, val, id;}sta[N];
	inline bool operator < (que a, que b) {return a.val<b.val;}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r; len[p]=r-l+1;
		if (l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void cover(int p, int l, int r) {
		if (sum[p]==len[p]) return ;
		if (l<=tl(p)&&r>=tr(p)) return void(sum[p]=len[p]);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) cover(p<<1, l, r);
		if (r>mid) cover(p<<1|1, l, r);
		sum[p]=sum[p<<1]+sum[p<<1|1];
	}
	void solve() {
		for (int i=1; i<=n; ++i) sta[++top]={i, i, a[i], 0};
		for (int i=1; i<=m; ++i) sta[++top]={::tl[i], ::tr[i], x[i], i};
		sort(sta+1, sta+top+1);
		build(1, 1, n);
		for (int i=1,l1,r1,l2,r2; i<=q; ++i) {
			l1=read(); r1=read(); l2=read(); r2=read(); ans=0;
			memset(sum, 0, sizeof(sum));
			for (int j=1,lst=0,len=r2-l2+1; j<=top&&sum[1]!=len; ++j) if ((sta[j].id==0||(l1<=sta[j].id&&sta[j].id<=r1))&&sta[j].r>=l2&&sta[j].l<=r2) {
				// cout<<"j: "<<j<<endl;
				cover(1, max(sta[j].l, l2), min(sta[j].r, r2));
				// cout<<"cover: "<<max(sta[j].l, l2)<<' '<<min(sta[j].r, r2)<<' '<<sta[j].val<<endl;
				ans+=1ll*sta[j].val*(sum[1]-lst);
				// cout<<sum[1]-lst<<endl;
				lst=sum[1];
			}
			printf("%lld\n", ans);
		}
	}
}

signed main()
{
	freopen("b.in", "r", stdin);
	freopen("b.out", "w", stdout);

	n=read(); m=read(); q=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	for (int i=1; i<=m; ++i) tl[i]=read(), tr[i]=read(), x[i]=read();
	// force::solve();
	// task1::solve();
	task::solve();

	return 0;
}
posted @ 2022-05-03 07:09  Administrator-09  阅读(5)  评论(2编辑  收藏  举报