Examples

P8349 [SDOI/SXOI2022] 整数序列 解题报告

P8349 [SDOI/SXOI2022] 整数序列 解题报告:

更好的阅读体验

题意

给定序列 \(a,b\)\(q\) 次询问两种颜色 \((x,y)\),定义一个区间的权值为其中 \(a\) 值为 \(x\)\(y\)\(b\) 值之和,求 \(x\) 数量等于 \(y\) 数量的子区间权值最大值。

\(1\leqslant n\leqslant 3\times 10^5,1\leqslant q\leqslant 10^6,\text{7s}\)

分析

轻视了这道题啊。

考虑根号分治,令阈值为 \(S\)

小集合对小集合直接把位置归并成一个序列暴力扫一遍即可,大集合对大集合可以直接暴力+记忆化,这里的复杂度是 \(O(qS+\frac{n^2}{S})\)

难点主要是小集合对大集合(令 \(x\) 为小集合,\(y\) 为大集合),我们发现我们将 \(x\)\(y\) 对应位置取出来之后,对于一个 \(y\) 连续段,只要其长度大到没有合法子区间能跨越它,那么它的长度就是无关紧要的了,可以缩到恰好满足条件的长度。

更具体地说,我们维护一个 \(y\) 坐标集合,对于每个长度为 \(x\) 的连续段,都向前找 \(x+1\) 个没加入集合的 \(y\) 加入集合,向后找 \(x+1\) 个没加入集合的 \(y\) 加入集合,那么保留集合内的 \(y\)\(x\) 进行运算也能保证答案的正确性。

而这样得到的集合大小是不超过 \(2S\) 的,那么我们得到了一个 \(O(qS\log n+\frac{n^2}{S})\) 的做法,令 \(S=\frac{n}{\sqrt{q\log n}}\) 就是 \(O(n\sqrt{q\log n})\) 了。

实际上这个 \(\log\) 可以去掉。我们离线,把询问挂在对应大集合上。

扫两遍,分开维护向左取的 \(y\) 和向右取的 \(y\),每次用一个栈维护若干个连续的连续段集合,判断新加入的集合能否和栈顶合并显然可以 \(O(1)\)。最后我们将每个连续段内部的 \(y\) 以及其向左(或向右)还能扩展的 \(y\) 加入集合即可。

这样的复杂度就是 \(O(qS+\frac{n^2}{S})\) 了,令 \(S=\frac{n}{\sqrt q}\) 即可得到 \(O(n\sqrt q)\) 的复杂度。

代码

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<map>
char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
using namespace std;
const int maxn=300005,maxq=1000005,S=300;
int n,m,ps,top,tmps,stp;
int a[maxn],b[maxn],stk[maxn][3],pos[maxn],tmp[maxn],tmpp[maxn],c[maxn],xx[maxq],yy[maxq],cnt[maxn],vis[maxn];
long long inf;
long long ans[maxq],mn[maxn<<1];
vector<int>v[maxn],q[maxn];
map<pair<int,int>,long long>mp;
long long solve(int x,int y){
	for(int i=1;i<=ps;i++)
		c[i]=c[i-1]+(a[pos[i]]==x? 1:-1);
	long long res=-1e18,s=0;
	mn[ps]=0;
	for(int i=1;i<=ps;i++)
		s+=b[pos[i]],res=max(res,s-mn[c[i]+ps]),mn[c[i]+ps]=min(mn[c[i]+ps],s);
	for(int i=0;i<=ps;i++)
		mn[c[i]+ps]=inf;
	return res;
}
void read(int &x){
	x=0;
	char c=getchar();
	int f=0;
	for(;c<'0'||c>'9';c=getchar())
		f|=(c=='-');
	for(;c>='0'&&c<='9';c=getchar())
		x=x*10+c-48;
	if(f==1)
		x=-x;
}
void print(long long x){
	if(x<0)
		putchar('-'),x=-x;
	if(x>9)
		print(x/10);
	putchar(x%10+48);
}
int main(){
//	freopen("tmp.in","r",stdin);
//	freopen("tmp.out","w",stdout);
	memset(mn,127,sizeof(mn)),inf=mn[0];
	read(n),read(m);
	for(int i=1;i<=n;i++)
		read(a[i]),v[a[i]].push_back(i);
	for(int i=1;i<=n;i++)
		read(b[i]);
	for(int t=1,x,y;t<=m;t++){
		read(x),read(y),xx[t]=x,yy[t]=y;
		if((v[x].size()>S)+(v[y].size()>S)==1){
			if(v[x].size()>S)
				q[x].push_back(t);
			else q[y].push_back(t);
			continue;
		}
		if(mp.count(make_pair(min(x,y),max(x,y)))){
			ans[t]=mp[make_pair(min(x,y),max(x,y))];
			continue;
		}
		int i=0,j=0;
		ps=0;
		while(i<v[x].size()||j<v[y].size()){
			if(i<v[x].size()&&(j==v[y].size()||v[x][i]<v[y][j]))
				pos[++ps]=v[x][i],i++;
			else pos[++ps]=v[y][j],j++;
		}
		ans[t]=mp[make_pair(min(x,y),max(x,y))]=solve(x,y);
	}
	for(int t=1;t<=n;t++)
		if(v[t].size()>S&&q[t].size()){
			for(int i=1;i<=n;i++)
				cnt[i]=cnt[i-1]+(a[i]==t);
			for(int p=0;p<q[t].size();p++){
				int k=q[t][p],r=xx[k]+yy[k]-t;
				ps=top=tmps=0,stp++;
				for(int i=0;i<v[r].size();i++)
					pos[++ps]=v[r][i];
				for(int i=0;i<v[r].size();i++){
					int j=i;
					while(j+1<v[r].size()&&cnt[v[r][j+1]-1]==cnt[v[r][j]])
						j++;
					int p=v[r][i],q=v[r][j],c=j-i+2;
					while(top){
						int w=cnt[p-1]-cnt[stk[top][2]];
						if(w<=c)
							p=stk[top][1],c=c+stk[top][3]-w,top--;
						else break;
					}
					top++,stk[top][0]=c,stk[top][1]=p,stk[top][2]=q,i=j;
				}
				int lst=0;
				for(int i=1;i<=top;i++){
					int c=stk[i][0],p=stk[i][1],q=stk[i][2];
					lst=max(lst,cnt[p]-c);
					while(lst<=cnt[q]-1){
						if(vis[v[t][lst]]!=stp)
							tmp[++tmps]=v[t][lst],vis[v[t][lst]]=stp;
						lst++;
					}
				}
				merge(pos+1,pos+1+ps,tmp+1,tmp+1+tmps,tmpp+1);
				int tmpps=ps+tmps;
				tmps=top=0;
				for(int i=v[r].size()-1;i>=0;i--){
					int j=i;
					while(j>=1&&cnt[v[r][j-1]]==cnt[v[r][j]-1])
						j--;
					int p=v[r][j],q=v[r][i],c=i-j+2;
					while(top){
						int w=cnt[stk[top][1]-1]-cnt[q];
						if(w<=c)
							q=stk[top][2],c=c+stk[top][3]-w,top--;
						else break;
					}
					top++,stk[top][0]=c,stk[top][1]=p,stk[top][2]=q,i=j;
				}
				lst=cnt[n]-1;
				for(int i=1;i<=top;i++){
					int c=stk[i][0],p=stk[i][1],q=stk[i][2];
					lst=min(lst,cnt[q]+c-1);
					while(lst>=cnt[p]){
						if(vis[v[t][lst]]!=stp)
							tmp[++tmps]=v[t][lst],vis[v[t][lst]]=stp;
						lst--;
					}
				}
				reverse(tmp+1,tmp+1+tmps),merge(tmpp+1,tmpp+1+tmpps,tmp+1,tmp+1+tmps,pos+1);
				ps=tmpps+tmps,ans[k]=solve(t,r);
			}
		}
	for(int i=1;i<=m;i++)
		print(ans[i]),putchar('\n');
	return 0;
}
posted @ 2022-05-17 18:35  xiaoziyao  阅读(151)  评论(0编辑  收藏  举报