专栏文章
题解:P11348 [KTSC 2023 R2] 团队建设
P11348题解参与者 1已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mipijh9b
- 此快照首次捕获于
- 2025/12/03 12:34 3 个月前
- 此快照最后确认于
- 2025/12/03 12:34 3 个月前
来点高贵的 polylog 做法。
前言
本篇题解将提供一个该题的 的 polylog 做法,不一定是最优复杂度,仅作抛砖引玉。
做法
首先证明此题中的单调性:设 表示第一个序列中选 对应的最优的第二个序列中的元素为 ,易证 单调不升。同理 对 也有同样的单调性。
接下来考虑所有询问中 时怎么做。设 ,对第一个序列建一棵线段树,对线段树上匹配上的每个区间求出这个区间里的最大值。对于线段树上的每个节点,考虑维护 中的每个元素对这个区间里的最优解,显然最优解相同的 是一个区间,维护区间长度个断点,查询时在端点上二分即可。
对于一般情况,我们对 再进行一个线段树分治,对于 的线段树的一个节点 ,我们再用一颗线段树去维护 中的区间对 的最优解。考虑如何建这一棵树,我们用类似决策单调性分治的方式去做,建树到 时维护对应的最优解可能存在的区间 ,将这个节点记为 。接着分类讨论:
- 如果 ,直接遍历 到 ,求出最优解。
- 如果 ,且 ,记 ,遍历 到 求出 的最优匹配为记为 ,然后向左右儿子分治到 ,
- 如果 ,且 ,在这棵节点上记录 代表整个区间的最优解,然后直接记录下此区间的最优解为 ,同时求出 对 的答案,当查询到此区间时,直接求出所查询的区间对 的答案。
易证这样建出的线段树一层最多只能有 个节点,线段树分治时所有的区间长度之和为 ,复杂度得以保证。
然后就做完了,复杂度理论上是 ,洛谷上取得了次优解,跑的还是挺快的。
CPP#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lc c<<1
#define rc c<<1|1
#define mid (l+r>>1)
#define pii pair<int,int>
#define mkp make_pair
#define fir first
#define sec second
#define pb push_back
const int N = 1e5+5;
ll A1[N],B1[N],A2[N],B2[N];
int n,m;
vector< pii >tr1[N<<2];
vector< int >tr2[N<<2];
ll F(ll x,ll y){return (A1[x] + A2[y])*(B1[x] + B2[y]);}
ll ans[N],tr3[N<<2],ty[N<<2];
int l1[N],r1[N],l2[N],r2[N];
void build1(int c,int l,int r)
{
//cerr<<c<<" "<<l<<" "<<r<<"\n";
for(int i = l;i <= r;i++)
{
while(!tr1[c].empty())
{
pii p = tr1[c].back();//cerr<<F(4,1)<<" "<<F(4,2)<<" "<<p.fir<<" "<<p.sec<<"\n";
if(F(-p.fir,i) > F(-p.fir,p.sec)) tr1[c].pop_back();
else break;
}
if(tr1[c].empty()) tr1[c].pb(mkp(-n,i));
else if(F(1,i) > F(1,tr1[c].back().sec))
{
pii p = tr1[c].back();
int L = 1,R = -p.fir-1;
//cerr<<"!"<<L<<" "<<R<<"\n";
while(L < R)
{
int Mid = (L+R>>1);
if(F(Mid+1,p.sec) < F(Mid+1,i)) L = Mid+1;//找到最后一个i > p的地方
else R = Mid;
}
//cerr<<F(L,1)<<" "<<F(L,2)<<"\n";
tr1[c].pb(mkp(-L,i));
}
}
//for(auto p:tr1[c]) cerr<<p.fir<<" "<<p.sec<<"\n";
//cerr<<c<<" "<<l<<" "<<r<<"\n";
if(l == r) return ;
build1(lc,l,mid),build1(rc,mid+1,r);
}
int Max(int x,int y,int z)
{
if(x == 0 || y == 0) return x^y;
return F(z,x) > F(z,y) ? x:y;
}
int Ask(int c,int l,int r,int ql,int qr,int x)
{
//cerr<<c<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<" "<<x<<"\n";
if(l >= ql && r <= qr)
{
auto pos = prev(upper_bound(tr1[c].begin(),tr1[c].end(),mkp(-x,m+1)));
auto p = *pos;
return p.sec;
}
int res = 0;
if(ql <= mid) res = Max(res,Ask(lc,l,mid,ql,qr,x),x);
if(qr > mid) res = Max(res,Ask(rc,mid+1,r,ql,qr,x),x);
return res;
}
void Ins(int c,int l,int r,int ql,int qr,int id)
{
if(l >= ql && r <= qr)
{
tr2[c].pb(id);
return ;
}
if(ql <= mid) Ins(lc,l,mid,ql,qr,id);
if(qr > mid) Ins(rc,mid+1,r,ql,qr,id);
}
void build3(int c,int l,int r,int ql,int qr)
{
//cerr<<"build3 "<<c<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<"\n";
ty[c] = 0;
if(ql == qr)
{
ty[c] = ql;
tr3[c] = F(ql,Ask(c,l,r,l,r,ql));//l,r这个区间全对应
return ;
}
ll qmid = ql;
for(int i = ql+1;i <= qr;i++) if(F(qmid,mid) < F(i,mid)) qmid = i;
if(l == r)
{
tr3[c] = F(qmid,mid);
//cerr<<"!!"<<tr3[c]<<" "<<qmid<<" "<<mid<<"\n";
return ;
}
build3(lc,l,mid,qmid,qr),build3(rc,mid+1,r,ql,qmid);
tr3[c] = max(tr3[lc],tr3[rc]);
}
ll Qry(int c,int l,int r,int ql,int qr)
{
if(ql <= l && qr >= r) return tr3[c];
if(ty[c])//如果全部相同,也就是ql~qr对应最大值都是ty[c]
{
//cerr<<"!!!"<<c<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<" "<<Ask(c,l,r,ql,qr,ty[c])<<"\n";
return F(ty[c],Ask(c,l,r,ql,qr,ty[c]));
}
ll res = 0;
if(ql <= mid) res = max(res,Qry(lc,l,mid,ql,qr));
if(qr > mid) res = max(res,Qry(rc,mid+1,r,ql,qr));
return res;
}
void build2(int c,int l,int r)
{
//cerr<<c<<" "<<l<<" "<<r<<"\n";
if(!tr2[c].empty())
{
build3(1,1,m,l,r);
for(auto id:tr2[c])
{
ans[id] = max(ans[id],Qry(1,1,m,l2[id],r2[id]));//,cerr<<"!!!"<<id<<" "<<Qry(1,1,n,l2[id],r2[id])<<"\n";
//cerr<<id<<" "<<Qry(1,1,m,l2[id],r2[id])<<"\n";
}
}
//cerr<<c<<" "<<l<<" "<<r<<"\n";
if(l == r) return ;
build2(lc,l,mid),build2(rc,mid+1,r);
}
vector<long long> build_teams(vector<int> a1, vector<int> b1, vector<int> a2, vector<int> b2, vector<int> L1, vector<int> R1, vector<int> L2, vector<int> R2)
{
//cerr<<"!!!\n";
n = a1.size(),m = a2.size();
for(int i = 1;i <= n;i++) A1[i] = a1[i-1],B1[i] = b1[i-1];
for(int i = 1;i <= m;i++) A2[i] = a2[i-1],B2[i] = b2[i-1];
//cerr<<"!!!\n";
build1(1,1,m);
int Q = L1.size();
for(int i = 1;i <= Q;i++)
{
l1[i] = L1[i-1]+1;
r1[i] = R1[i-1]+1;
l2[i] = L2[i-1]+1;
r2[i] = R2[i-1]+1;
Ins(1,1,n,l1[i],r1[i],i);
//cout<<Qry(l1,r1,l2,r2)<<"\n";
}
//cerr<<"!!!\n";
build2(1,1,n);
vector<ll>res;
for(int i = 1;i <= Q;i++) res.pb(ans[i]);
return res;
}
/*
過ぎ去った季節を待って
思い出せなくて嫌になって
離ればなれから飛び立って
鳥も鳴いてたろ 鳴いてたろ
いつだって僕らを待ってる
疲れた痛みや傷だって
変わらないままの夜だって
歌い続けるよ 続けるよ
*/
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...