我记得当年好像 vp 过这场,但是他质量真的好高。
整数序列
数据范围很诈骗,但 poly log 做法思考无果还是指引我们来想 sqrt 做法。
首先有一个很暴力的 \(O(cnt_x+cnt_y)\) 的做法。看到和出现次数有关则可以想根号分治。我们设定一个阈值 \(B\),对于两者都 \(<B\) 的部分可以暴力做,都大于 \(B\) 的部分也可以暴力做,因为这样的最多只会有 \(n^2/B\) 次计算。
然后思考一大一小,容易发现两者顺序无关,不妨设 \(cnt_x>cnt_y\)。
那么容易想到 \(x\) 中有很多是不必要的部分。实际上只有 \(y\) 中每个极长元素段在 \(x\) 中的相同长度的前驱和后继才是必要的。然而还有一个问题就是这样不合法的情况有可能变合法,那么我们不妨再放入一段前驱的前驱段。这样就把 \(x\) 的长度变得和 \(y\) 同阶了。
总的预处理复杂度变为 \(O(\frac{n^2}{B})\),总复杂度 \(O(\frac{n^2}{B}+qB)\),取 \(B=\frac{n}{\sqrt{q}}\) 即可得到 \(O(n\sqrt{q})\)。
实现细节可以考虑离线询问,然后预处理前驱后继,全部归并排序后再去重。
#include<bits/stdc++.h>
#define pb push_back
#define pii pair<int,int>
#define MP make_pair
#define F first
#define S second
using namespace std;
typedef long long ll;
const int maxn=2e6+5;
const ll inf=0x3f3f3f3f3f3f3f3f;
template<typename T>
void read(T &x){
T sgn=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')sgn=-1;
for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
x*=sgn;
}
int n,m,a[maxn],b[maxn],num;
int B,pre[maxn],nxt[maxn],len;
int d[maxn],e[maxn],f[maxn],g[maxn];
vector<int>vec[maxn];
vector<pii>qry[maxn];
ll s1[maxn],s2[maxn],mp[maxn];
pii c[maxn];
bool vis[maxn],mark[maxn],zz[maxn];
map<pii,ll> ans;
ll Ans[maxn];
ll BF(){
ll now=-inf;
vis[n]=1;mp[n]=0;
for(int k=1;k<=len;k++){
s1[k]=s1[k-1]+b[c[k].S];
s2[k]=s2[k-1]+c[k].F;
if(vis[s2[k]+n])now=max(now,s1[k]-mp[s2[k]+n]);
if(!vis[s2[k]+n])mp[s2[k]+n]=s1[k],vis[s2[k]+n]=1;
else mp[s2[k]+n]=min(mp[s2[k]+n],s1[k]);
}
vis[n]=0;
for(int k=1;k<=len;k++)vis[s2[k]+n]=0;
return now;
}
int main(){
read(n);read(m);
for(int i=1;i<=n;i++)read(a[i]),vec[a[i]].pb(i);
for(int i=1;i<=n;i++)if(vec[i].size())num++;
for(int i=1;i<=n;i++)read(b[i]);
B=n/sqrt(m)+1;
for(int i=1;i<=m;i++){
int x,y;
read(x);read(y);
if(ans.find(MP(x,y))!=ans.end()){Ans[i]=ans[MP(x,y)];continue;};
if(((int)vec[x].size()<B&&(int)vec[y].size()<B)||((int)vec[x].size()>=B&&(int)vec[y].size()>=B)){
len=0;
for(int p=0,q=0;p<(int)vec[x].size()||q<(int)vec[y].size();){
if(p>=(int)vec[x].size())c[++len]=MP(-1,vec[y][q++]);
else if(q>=(int)vec[y].size())c[++len]=MP(1,vec[x][p++]);
else{
if(vec[x][p]<vec[y][q])c[++len]=MP(1,vec[x][p++]);
else c[++len]=MP(-1,vec[y][q++]);
}
}
Ans[i]=ans[MP(x,y)]=ans[MP(y,x)]=BF();
}else{
if(vec[x].size()<vec[y].size())swap(x,y);
qry[x].pb(MP(y,i));
}
}
for(int i=1;i<=n;i++)if(qry[i].size()){
for(int j:vec[i])mark[j]=1;
for(int j=1;j<=n;j++){
pre[j]=pre[j-1];
if(mark[j-1])pre[j]=j-1;
}
nxt[n+1]=n+1;
for(int j=n;j;j--){
nxt[j]=nxt[j+1];
if(mark[j+1])nxt[j]=j+1;
}
for(pii o:qry[i]){
int j=o.F;
if(ans.find(MP(i,j))!=ans.end()){
Ans[o.S]=ans[MP(i,j)];
continue;
}
len=0;
int u=0,v=0,w=0,tmp=0;
for(int k:vec[j]){
if(nxt[k]<=n){
if(nxt[k]>tmp)d[++u]=tmp=nxt[k];
else if(nxt[tmp]<=n)d[++u]=tmp=nxt[tmp];
}
}
tmp=n+1;
for(int l=(int)vec[j].size()-1;~l;l--){
int k=vec[j][l];
if(pre[k]){
if(pre[k]<tmp)e[++v]=tmp=pre[k];
else if(pre[tmp])e[++v]=tmp=pre[tmp];
if(pre[tmp])e[++v]=tmp=pre[tmp];
}
}
reverse(e+1,e+1+v);
for(int p=1,q=1;p<=u||q<=v;){
if(p>u)f[++w]=e[q++];
else if(q>v)f[++w]=d[p++];
else{
if(d[p]<e[q])f[++w]=d[p++];
else f[++w]=e[q++];
}
}
for(int p=1,q=0;p<=w||q<(int)vec[j].size();){
if(p>w)g[++len]=vec[j][q++];
else if(q>=(int)vec[j].size())g[++len]=f[p++];
else{
if(f[p]<vec[j][q])g[++len]=f[p++];
else g[++len]=vec[j][q++];
}
}
tmp=len;len=0;
for(int k=1;k<=tmp;k++){
if(g[k]!=g[len])g[++len]=g[k];
}
for(int k=1;k<=len;k++){
c[k].F=a[g[k]]==i?1:-1;
c[k].S=g[k];
}
Ans[o.S]=ans[MP(i,j)]=ans[MP(j,i)]=BF();
for(int k=1;k<=len;k++)if(a[c[k].S]==i)zz[c[k].S]=0;
}
for(int j:vec[i])mark[j]=0;
}
for(int i=1;i<=m;i++)printf("%lld\n",Ans[i]);
return 0;
}