P8349 题解
donghanwen1225 · · 题解
upd on
SDOI 2022 D1T1。在考场上没有想出来小块对大块的做法,写了个
Part 1 : 考虑暴力该怎么做。
对于每次询问,首先我们将
那么题意可以转化为,找出一个区间
设当前考虑到了第
考虑维护当前每个
时间复杂度为
Part 2 : 考虑根号平衡。
思考为什么上面的暴力无法通过此题。假设
我们根据
下面分三类讨论:
1. 小块对小块。显然直接套用暴力即可。复杂度为
2. 大块对大块。因为大块的长度要超过 unordered_map 存下来,如果遇到相同的询问直接调用答案即可),直接套用暴力,这部分的复杂度最大为
3. 小块对大块。现在我们不能将两部分直接拼起来了。
考虑利用小块的大小不超过
显然,小块中每个点都是需要考虑在内的有效点。
然而大块中,许多点对答案是不可能产生贡献的。这是因为,选中的区间
具体的,我们仍然考虑
设
另外注意,若 set 去快速维护。
得到有效点后将其离散化,再套用暴力即可。有效点的个数始终只与大小
考虑到大块的数量不多,且复杂度取决于实际的小块长度,这部分的复杂度应当为
大块对大块的复杂度较小直接忽略,总复杂度为
按理论计算出来
代码中为了简便,拓展
upd 1:补充大块对大块、小块对大块的复杂度的证明。
大块对大块:假设有
考虑令这
由于
小块对大块:设有
考虑到小块对大块的复杂度只取决于小块长度,我们用最长的
最强的情况下,可构造
code:
#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
#include<vector>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int blo=300;
int n,q,x,y,a[300005],len[300005],st[300005],tim[300005],pre[300005],cl[300005];
ll b[300005],mn[300005];unordered_map<int,ll> mp[300005];set<int> pos[300005];
struct node{int id;ll v;} xl[300005];
vector<node> tj[300005];vector<ll> qz[300005];
template<typename T> void Read(T &x)
{
x=0;bool f=0;
char ch=getchar();
while(ch<'0'||ch>'9') f=f||(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
x=f==0?x:-x;
}
int main()
{
Read(n);Read(q);
for(int i=1;i<=n;i++) Read(a[i]),tim[i]=tim[pre[a[i]]]+1,pre[a[i]]=i;
for(int i=1;i<=n;i++) Read(b[i]);
for(int i=1;i<=n;i++) tj[a[i]].push_back({i,b[i]}),pos[a[i]].insert(i);
for(int i=1;i<=n;i++)
if(tj[i].size())
{
len[i]=tj[i].size();qz[i].resize(len[i]+1);
for(int j=0;j<len[i];j++) qz[i][j+1]=qz[i][j]+tj[i][j].v;
}
for(int i=0;i<=n;i++) mn[i]=1ll<<60;
while(q--)
{
Read(x);Read(y);
if(mp[x].find(y)!=mp[x].end()){printf("%lld\n",mp[x][y]);continue;}
if((len[x]>blo&&len[y]>blo)||(len[x]+len[y]<=blo))
{
int tl=0,tr=0;ll ans=-(1ll<<60);
while(tl<len[x]&&tr<len[y])
{
if(tj[x][tl].id<tj[y][tr].id) xl[tl+tr]=tj[x][tl],tl++;
else xl[tl+tr]=tj[y][tr],tr++;
}
while(tl<len[x]) xl[tl+tr]=tj[x][tl],tl++;
while(tr<len[y]) xl[tl+tr]=tj[y][tr],tr++;
int cur1=0,cur2=0;
for(int i=0;i<len[x]+len[y];i++)
{
if(a[xl[i].id]==x) cur1++;
if(a[xl[i].id]==y) cur2++;
int sl=cur1-cur2+len[y];
if(sl==len[y]) ans=max(ans,qz[x][cur1]+qz[y][cur2]);
ans=max(ans,qz[x][cur1]+qz[y][cur2]-mn[sl]);
mn[sl]=min(mn[sl],qz[x][cur1]+qz[y][cur2]);cl[i]=sl;
}
mp[x][y]=mp[y][x]=ans;printf("%lld\n",ans);
for(int i=0;i<len[x]+len[y];i++) mn[cl[i]]=1ll<<60;
}
else
{
if(len[x]>len[y]) swap(x,y);
int top=0;ll ans=-(1ll<<60);
for(int i=0;i<len[x];i++)
{
if(!pos[y].size()) continue;
auto tmp=pos[y].lower_bound(tj[x][i].id);
if(tmp==pos[y].begin()) continue;--tmp;st[++top]=*tmp;
auto del=tmp;if(tmp==pos[y].begin()) continue;--tmp;
st[++top]=*tmp;pos[y].erase(del);pos[y].erase(tmp);
}
for(int i=0;i<len[x];i++)
{
if(!pos[y].size()) continue;
auto tmp=pos[y].upper_bound(tj[x][i].id);
if(tmp==pos[y].end()) continue;st[++top]=*tmp;
auto del=tmp;++tmp;if(tmp==pos[y].end()) continue;
st[++top]=*tmp;pos[y].erase(del);pos[y].erase(tmp);
}
for(int i=1;i<=top;i++) pos[y].insert(st[i]);
for(int i=0;i<len[x];i++) st[++top]=tj[x][i].id;
sort(st+1,st+1+top);int cnt=unique(st+1,st+1+top)-st-1;
for(int i=1;i<=cnt;i++) xl[i]={st[i],b[st[i]]};
int cur1=0,cur2=0,las1=0,las2=0;
for(int i=1;i<=cnt;i++)
{
if(a[xl[i].id]==x) cur1+=tim[xl[i].id]-las1,las1=tim[xl[i].id];
if(a[xl[i].id]==y) cur2+=tim[xl[i].id]-las2,las2=tim[xl[i].id];
int sl=cur2-cur1+len[x];
if(sl==len[x]) ans=max(ans,qz[x][cur1]+qz[y][cur2]);
ans=max(ans,qz[x][cur1]+qz[y][cur2]-mn[sl]);
mn[sl]=min(mn[sl],qz[x][cur1]+qz[y][cur2]);cl[i]=sl;
}
mp[x][y]=mp[y][x]=ans;printf("%lld\n",ans);
for(int i=1;i<=cnt;i++) mn[cl[i]]=1ll<<60;
}
}
return 0;
}