题解 整数序列

传送门

《关于我先猜是根号分治然后发现时限是 7s 于是联想到这可能是 SDOI2022 Day1T1 这个事》

首先有一个 \(O(siz_{涉及到的两种颜色})\) 的处理两种颜色的做法,可以处理 大-大,小-小
然后 大-小 怎么办呢?
令块长为 \(B\),那么对较小的颜色枚举区间是 \(O(B^2)\) 的,再对每个区间枚举可行的较大颜色区间是 \(O(B^3)\)
猜测跑不满,于是将块长调成 \(n^{\frac{1}{3}}\) 可以通过
赛后发现 \(B\in[n^{\frac{1}{10}}, n^{\frac{1}{2}}]\) 均可以通过

然后正解是怎么处理 大-小 的呢?
每有一个小的颜色,就向两边扩展一个大的颜色
只有被扩展到的大的颜色是有用的(因为最后要求两种颜色出现的次数一样)
这样复杂度严格 \(O(n\sqrt n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 300010
#define fir first
#define sec second
#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*f;
}

int n, q;
ll a[N], b[N];

namespace force{
	int top;
	ll tem[N<<1], *pre=tem+N;
	vector<int> pos[N];
	pair<int, ll> sta[N];
	map<pair<int, int>, ll> mp;
	void solve() {
		for (int i=1; i<=n; ++i) pos[a[i]].pb(i);
		for (int i=1,x,y; i<=q; ++i) {
			// cout<<"i: "<<i<<endl;
			x=read(); y=read();
			if (!pos[x].size()||!pos[y].size()) {cout<<"-1"<<endl; continue;}
			if (mp.find({x, y})!=mp.end()) {printf("%lld\n", mp[{x, y}]); continue;}
			int p1=0, p2=0; top=0;
			while (p1<pos[x].size()||p2<pos[y].size()) {
				int minn=n+1;
				if (p1<pos[x].size()) minn=min(minn, pos[x][p1]);
				if (p2<pos[y].size()) minn=min(minn, pos[y][p2]);
				if (p1<pos[x].size()&&minn==pos[x][p1]) sta[++top]={1, b[pos[x][p1++]]};
				if (p2<pos[y].size()&&minn==pos[y][p2]) sta[++top]={-1, b[pos[y][p2++]]};
			}
			int cnt=0, l, r;
			ll sum=0, ans=-INF;
			pre[l=r=0]=0;
			for (int j=1; j<=top; ++j) {
				cnt+=sta[j].fir; sum+=sta[j].sec;
				while (l>cnt) pre[--l]=INF;
				while (r<cnt) pre[++r]=INF;
				ans=max(ans, sum-pre[cnt]);
				pre[cnt]=min(pre[cnt], sum);
			}
			printf("%lld\n", mp[{x, y}]=ans);
		}
	}
}

namespace task1{
	int cnt[N], lst[N], nxt[N], top, sqr;
	pair<int, ll> sta[N];
	vector<int> pos[N];
	vector<pair<int, int>> que[N];
	map<pair<int, int>, ll> mp;
	ll tem[N<<1], *pre=tem+N, ans[1000010], sum[N];
	inline int qcnt(int l, int r) {return cnt[r]-cnt[max(l-1, 0)];}
	inline ll qsum(int l, int r) {return sum[r]-sum[max(l-1, 0)];}
	ll solve1(int x, int y) {
		if (x>y) swap(x, y);
		if (mp.find({x, y})!=mp.end()) return mp[{x, y}];
		int p1=0, p2=0; top=0;
		while (p1<pos[x].size()||p2<pos[y].size()) {
			int minn=n+1;
			if (p1<pos[x].size()) minn=min(minn, pos[x][p1]);
			if (p2<pos[y].size()) minn=min(minn, pos[y][p2]);
			if (p1<pos[x].size()&&minn==pos[x][p1]) sta[++top]={1, b[pos[x][p1++]]};
			if (p2<pos[y].size()&&minn==pos[y][p2]) sta[++top]={-1, b[pos[y][p2++]]};
		}
		int cnt=0, l, r;
		ll sum=0, ans=-INF;
		pre[l=r=0]=0;
		for (int j=1; j<=top; ++j) {
			cnt+=sta[j].fir; sum+=sta[j].sec;
			while (l>cnt) pre[--l]=INF;
			while (r<cnt) pre[++r]=INF;
			ans=max(ans, sum-pre[cnt]);
			pre[cnt]=min(pre[cnt], sum);
		}
		return mp[{x, y}]=ans;
	}
	void solve() {
		sqr=pow(n, 0.3);
		// cout<<"sqr: "<<sqr<<endl;
		for (int i=1; i<=n; ++i) pos[a[i]].pb(i);
		for (int i=1,x,y; i<=q; ++i) {
			x=read(); y=read();
			if (!pos[x].size()||!pos[y].size()) {ans[i]=-1; continue;}
			if (pos[x].size()>pos[y].size()) swap(x, y);
			int sizx=pos[x].size(), sizy=pos[y].size();
			if (sizx<=sqr&&sizy<=sqr) ans[i]=solve1(x, y);
			else if (sizx>sqr&&sizy>sqr) ans[i]=solve1(x, y);
			else que[y].pb({x, i});
		}
		for (int i=1; i<=n; ++i) if (pos[i].size()&&pos[i].size()>sqr) {
			// cout<<"i: "<<i<<endl;
			for (int j=1; j<=n+1; ++j) cnt[j]=cnt[j-1]+(a[j]==i);
			for (int j=1; j<=n+1; ++j) sum[j]=sum[j-1]+(a[j]==i)*b[j];
			for (int j=1,t=0; j<=n+1; ++j) lst[j]=t, t=a[j]==i?j:t;
			for (int j=n,t=n+1; j; --j) nxt[j]=t, t=a[j]==i?j:t;
			for (auto it:que[i]) {
				// cout<<"it: "<<it.fir<<endl;
				if (mp.find({min(it.fir, i), max(it.fir, i)})!=mp.end()) {ans[it.sec]=mp[{min(it.fir, i), max(it.fir, i)}]; continue;}
				ll val=-INF;
				// cout<<"pos_x: "; for (auto it:pos[i]) cout<<it<<' '; cout<<endl;
				// cout<<"pos_y: "; for (auto t:pos[it.fir]) cout<<t<<' '; cout<<endl;
				for (int p1=0; p1<pos[it.fir].size(); ++p1) {
					ll pre=0;
					for (int p2=p1; p2<pos[it.fir].size(); ++p2) {
						int need=p2-p1+1;
						// cout<<"need: "<<need<<endl;
						int real=qcnt(pos[it.fir][p1], pos[it.fir][p2]);
						pre+=b[pos[it.fir][p2]];
						if (real>need) continue;
						else if (real==need) val=max(val, pre+qsum(pos[it.fir][p1], pos[it.fir][p2]));
						else {
							int l=pos[it.fir][p1], r=pos[it.fir][p2];
							// int dlt=min(need-real, min(cnt[l], qcnt(r, n)));
							int t1=l, t2=r;
							// cout<<"lr: "<<t1<<' '<<t2<<endl;
							int liml=0, limr=n+1;
							if (p2+1<pos[it.fir].size()) limr=min(limr, pos[it.fir][p2+1]);
							if (p1) liml=max(liml, pos[it.fir][p1-1]);
							// cout<<"lim: "<<liml<<' '<<limr<<endl;
							while (t2<limr&&qcnt(t1, t2)<need) t2=nxt[t2];
							// cout<<lst[t1]<<' '<<lst[t2]<<endl;
							if (t2>=limr) t2=max(lst[t2], r);
							// cout<<"need&now: "<<need<<' '<<qcnt(t1, t2)<<endl;
							while (t1>liml&&qcnt(t1, t2)<=need) {
								// cout<<"try: "<<t1<<' '<<t2<<' '<<qcnt(t1, t2)<<endl;
								assert(t2<limr);
								if (t1>liml&&t2<limr&&qcnt(t1, t2)==need) val=max(val, pre+qsum(t1, t2)); //, cout<<"t: "<<t1<<' '<<t2<<endl;
								if (qcnt(t1, t2)==need) t2=max(lst[t2], r);
								t1=lst[t1]; //t2=max(lst[t2], r);
							}
						}
						ans[it.sec]=mp[{min(it.fir, i), max(it.fir, i)}]=val;
					}
				}
			}
		}
		for (int i=1; i<=q; ++i) printf("%lld\n", ans[i]);
	}
}

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

	n=read(); q=read();
	bool flag=1;
	for (int i=1; i<=n; ++i) a[i]=read();
	for (int i=1; i<=n; ++i) if ((b[i]=read())<0) flag=0;
	// force::solve();
	// if (n<=5000) force::solve();
	// else task1::solve();
	task1::solve();

	return 0;
}
posted @ 2022-05-25 08:21  Administrator-09  阅读(1)  评论(0编辑  收藏  举报