题解:P11348 [KTSC 2023 R2] 团队建设
来点高贵的 polylog 做法。
前言
本篇题解将提供一个该题的
做法
首先证明此题中的单调性:设
接下来考虑所有询问中
对于一般情况,我们对
- 如果
L = R ,直接遍历ql 到qr ,求出最优解。 - 如果
L \neq R ,且ql\neq qr ,记mid = \lfloor \frac {L+R}{2}\rfloor ,遍历ql 到qr 求出mid 的最优匹配为记为qmid ,然后向左右儿子分治到(L,mid,qmid,qr) ,(mid+1,R,ql,qmid) - 如果
L\neq R ,且ql = qr ,在这棵节点上记录ql 代表整个区间的最优解,然后直接记录下此区间的最优解为ql ,同时求出[L,R] 对ql 的答案,当查询到此区间时,直接求出所查询的区间对ql 的答案。
易证这样建出的线段树一层最多只能有
然后就做完了,复杂度理论上是
#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;
}
/*
過ぎ去った季節を待って
思い出せなくて嫌になって
離ればなれから飛び立って
鳥も鳴いてたろ 鳴いてたろ
いつだって僕らを待ってる
疲れた痛みや傷だって
変わらないままの夜だって
歌い続けるよ 続けるよ
*/