题解 麻烦的杂货店

传送门

首先 \(O(n^2\log n)\) 可以离线下来归并做
然后发现可以对每个询问区间分治
答案一定是左,右边最大值或最左,右边的 \(max(min_l, min_r)\) 构成的区间
于是有一个 \(O(m\log^2 n)\) 的做法
可以 ST 表优化到 \(O(m\log n+n\log^2 n)\)? 没细想

然后正解是这样的:
先转化到前缀和序列上
考虑答案区间,其左右端点一定是相等的,且为区间 \(\min\)
于是 ST 表查询区间最左,右的最小值的位置 \(l, r\)
预处理 \(pre_i, nxt_i\) 分别表示在 \(i\) 前/后离 \(i\) 最远的 \(j\) 满足 \(sum_i=sum_j\)\(\min(i, j)=sum_i\)
这样其实构造了一个性质:
设询问区间为 \([x, y]\),则 \([x, l)\) 内的 \(\max(nxt_i)<l\),右边同理
并不知道如何想到这样的构造
于是答案即为 \(\max\{r-l, \operatorname{qmax}(x, l-1), \operatorname{qmax}(r+1, y)\}\)

复杂度 \(O(m+n\log n)\)

点击查看代码
#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

int n, m;
char s[N];
int a[N];

namespace force{
	int pre[N], ans[N], top;
	struct que{int fir, sec, rk;}q[N], sta[N];
	vector<int> able[N];
	int tl[N<<2], tr[N<<2], val[N<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define val(p) val[p]
	#define pushup(p) val(p)=min(val(p<<1), val(p<<1|1))
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) {val(p)=pre[l]; return ;}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		pushup(p);
	}
	int query(int p, int l, int r) {
		if (l<=tl(p)&&r>=tr(p)) return val(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid && r>mid) return min(query(p<<1, l, r), query(p<<1|1, l, r));
		else if (l<=mid) return query(p<<1, l, r);
		else return query(p<<1|1, l, r);
	}
	void solve() {
		for (int i=1; i<=n; ++i) pre[i]=pre[i-1]+a[i];
		build(1, 1, n);
		for (int i=1; i<=n; ++i)
			for (int j=i; j<=n; ++j)
				if (pre[j]-pre[i-1]==0 && query(1, i, j)>=pre[i-1]) able[i].pb(j);
		for (int i=1; i<=m; ++i) scanf("%d%d", &q[i].fir, &q[i].sec), q[i].rk=i;
		sort(q+1, q+m+1, [](que a, que b){return a.sec<b.sec;});
		for (int i=1; i<=n; ++i) {
			top=0;
			for (int j=1; j<=m; ++j) if (q[j].fir<=i&&q[j].sec>=i) sta[++top]=q[j];
			int pos=1, now=0;
			for (auto it:able[i]) {
				while (pos<=top && sta[pos].sec<it) ans[sta[pos].rk]=max(ans[sta[pos].rk], now), ++pos;
				now=it-i+1;
			}
			while (pos<=top) ans[sta[pos].rk]=max(ans[sta[pos].rk], now), ++pos;
		}
		for (int i=1; i<=m; ++i) printf("%d\n", ans[i]);
	}
}

namespace task{
	int pre[N], nxt[N], sum[N], buc[N], lg[N];
	int stl[20][N], str[20][N], stn[20][N], stp[20][N];
	inline int hmin(int a, int b) {return sum[a]<=sum[b]?a:b;}
	void init() {
		int *l=stl[0], *r=str[0], *u=stn[0], *v=stp[0];
		memset(pre, -1, sizeof(pre));
		memset(nxt, -1, sizeof(nxt));
		memset(buc, -1, sizeof(buc));
		for (int i=1; i<=n; ++i) sum[i]=sum[i-1]+a[i];
		buc[sum[0]]=0;
		for (int i=1; i<=n; ++i) {
			if (sum[i-1]>sum[i]) buc[sum[i-1]]=-1;
			if (~buc[sum[i]]) pre[nxt[buc[sum[i]]]=i]=buc[sum[i]];
			buc[sum[i]]=i;
		}
		for (int i=1; i<=n; ++i) {
			if (~pre[i] && ~pre[pre[i]]) pre[i]=pre[pre[i]];
			v[i]=(~pre[i])?i-pre[i]:0;
		}
		for (int i=n; ~i; --i) {
			if (~nxt[i] && ~nxt[nxt[i]]) nxt[i]=nxt[nxt[i]];
			u[i]=(~nxt[i])?nxt[i]-i:0;
		}
		for (int i=1; i<=n; ++i) l[i]=r[i]=i;
		#if 0
		cout<<"sum: "; for (int i=0; i<=n; ++i) cout<<setw(2)<<sum[i]<<' '; cout<<endl;
		cout<<"pos: "; for (int i=0; i<=n; ++i) cout<<setw(2)<<i<<' '; cout<<endl;
		cout<<"pre: "; for (int i=0; i<=n; ++i) cout<<setw(2)<<pre[i]<<' '; cout<<endl;
		cout<<"nxt: "; for (int i=0; i<=n; ++i) cout<<setw(2)<<nxt[i]<<' '; cout<<endl;
		cout<<"u  : "; for (int i=0; i<=n; ++i) cout<<setw(2)<<u[i]<<' '; cout<<endl;
		cout<<"v  : "; for (int i=0; i<=n; ++i) cout<<setw(2)<<v[i]<<' '; cout<<endl;
		#endif
	}
	void build() {
		for (int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
		int t=lg[n]-1;
		for (int j=1; j<=t; ++j) {
			for (int i=0; i+(1<<j)-1<=n; ++i) {
				stl[j][i]=hmin(stl[j-1][i], stl[j-1][i+(1<<(j-1))]);
				str[j][i]=hmin(str[j-1][i+(1<<(j-1))], str[j-1][i]);
				stn[j][i]=max(stn[j-1][i], stn[j-1][i+(1<<(j-1))]);
				stp[j][i]=max(stp[j-1][i], stp[j-1][i+(1<<(j-1))]);
			}
		}
	}
	inline int qmax(int (*st)[N], int l, int r) {
		int t=lg[r-l+1]-1;
		return max(st[t][l], st[t][r-(1<<t)+1]);
	}
	void solve() {
		init(); build();
		for (int i=1,x,y,l,r,ans; i<=m; ++i) {
			scanf("%d%d", &x, &y); --x;
			int t=lg[y-x+1]-1;
			l=hmin(stl[t][x], stl[t][y-(1<<t)+1]);
			r=hmin(str[t][y-(1<<t)+1], str[t][x]);
			//cout<<"lr: "<<l<<' '<<r<<endl;
			ans=r-l;
			if (l>x) ans=max(ans, qmax(stn, x, l-1));
			if (r<y) ans=max(ans, qmax(stp, r+1, y));
			printf("%d\n", ans);
		}
	}
}

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

	scanf("%d%d%s", &n, &m, s+1);
	for (int i=1; i<=n; ++i) a[i]=(s[i]=='F')?1:-1;
	// force::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-02-21 19:01  Administrator-09  阅读(2)  评论(0编辑  收藏  举报