传送门:loj2470
详见2018国家集训队论文《浅谈保序回归问题》(高睿泉)。
这里仅仅谈一下针对此题( L 1 L_1 L1问题)的普遍解法,整体二分:
一些约定:
这里规定问题中 p = 1 p=1 p=1。
存在引理:
证明有点繁琐,而且我没看懂QWQ,感性理解一下吧。
由此引理得到:
假设最优解不落在 ( a , b ) (a,b) (a,b)中,通过一组 S = { a , b } S=\{a,b\} S={a,b}问题的最优解,就可以知道某一组原问题最优解中 z i z_i zi与 a , b a,b a,b的相对大小关系。
而对于 L 1 L_1 L1问题,显然最优解一定在 y i y_i yi构成的集合 { Y 1 , Y 2 , . . . , Y m } ( ∀ i < m , Y i < Y i + 1 ) \{Y_1,Y_2,...,Y_m\}(\forall i<m,Y_i<Y_{i+1}) {Y1,Y2,...,Ym}(∀i<m,Yi<Yi+1)中,所以在集合上做整体二分:二分到区间 [ Y l , Y r ] [Y_l,Y_r] [Yl,Yr]时,判断 S = { Y m i d , Y m i d + 1 } S=\{Y_{mid},Y_{mid+1}\} S={Ymid,Ymid+1}问题的最优解,根据 z i S z_i^S ziS,把点分别划分到 Y [ l , m i d ] Y_{[l,mid]} Y[l,mid]和 Y [ m i d + 1 , r ] Y_{[mid+1,r]} Y[mid+1,r]中。
小拓展:
一般偏序集上的 L 1 L_1 L1问题,对应的 S S S问题可以看做简单的 01 01 01决策问题,而 f i ≤ f j f_i\leq f_j fi≤fj的限制相当于 f i = 1 f_i=1 fi=1时 f j ≠ 0 f_j\neq 0 fj̸=0,等价于最小权闭合子图问题,跑最小割解决。
1 < p < ∞ 1<p<\infty 1<p<∞的情况变成实数上二分即可。
套用上述 L 1 L_1 L1问题结论进行整体二分:
图仅仅是个基环树,网络流太逊了,考虑DP:
把图看做无向图,每条边 t y p i = 0 / 1 typ_i=0/1 typi=0/1分别表示 ≥ , ≤ \geq ,\leq ≥,≤的相对大小关系限制,设 f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1]分别表示点 i i i取值 v m i d / v m i d + 1 v_{mid}/v_{mid+1} vmid/vmid+1时的子树的最小代价。
对于基环树:先把环找出来,强制一个点为0/1后DP转移即可。
p.s 记得记录转移时的后继状态(划分0/1用)
#include
#define min(a,b) ((a)<(b)?(a):(b))
#define RI register
using namespace std;
const int N=3e5+10;
typedef long long ll;
const ll inf=1e18;
int n,m,id[N],d[N],w[N],v[N],num,cir;
int head[N],to[N<<1],nxt[N<<1],tot=1;
ll ans,g[N][2],f[N][2];
bool vs[N],cn[N],sid[N],dr[N][2],typ[N<<1],chg;
char buf[(1<<15)];int p1=0,p2=0;
inline char gc()
{
if(p1==p2) p1=0,p2=fread(buf,1,(1<<15),stdin);
return (p1==p2)?EOF:buf[p1++];
}
char cp;
inline void rd(int &x)
{
cp=gc();x=0;
for(;!isdigit(cp);cp=gc());
for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
}
inline void lk(int u,int v,bool tp)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;typ[tot]=tp;}
void ck(int x,int fr)
{
vs[x]=true;//if(cir) return;
for(RI int j,i=head[x];i;i=nxt[i])
if(cn[(j=to[i])] && (j!=fr)){
if(vs[j]) cir=i;
else ck(j,x);
}
}
void dfs(int x,int fr)
{
f[x][0]=g[x][0];f[x][1]=g[x][1];
for(RI int j,i=head[x];i;i=nxt[i])
if( cn[j=to[i]] && (j!=fr) && (i!=(cir^1))){
if(i==cir) {if(typ[i]!=chg) f[x][typ[i]]=inf;}
else{
dfs(j,x);
f[x][typ[i]]+=f[j][dr[j][typ[i]] = typ[i]];
f[x][typ[i]^1]+=f[j][dr[j][typ[i]^1] = (f[j][1]<f[j][0])];
f[x][0]=min(f[x][0],inf);f[x][1]=min(f[x][1],inf);
}
}
}
void gt(int x,bool tp,int fr)
{
sid[x]=tp;
for(RI int j,i=head[x];i;i=nxt[i])
if(cn[j=to[i]] && (j!=fr) && (i!=cir) && (i!=(cir^1)))
gt(j,dr[j][tp],x);
}
void sol(int l,int r,int ql,int qr)
{
if(ql>qr) return;
if(l==r){
for(RI int i=ql;i<=qr;++i) ans+=(ll)w[id[i]]*abs(d[id[i]]-v[l]);
return;
}
RI int x,i,j,mid=(l+r)>>1,tl=ql-1,tr;ll a,b;
for(i=ql;i<=qr;++i){x=id[i];
cn[x]=true;sid[x]=false;
g[x][0]=(ll)w[x]*abs(d[x]-v[mid]);
g[x][1]=(ll)w[x]*abs(d[x]-v[mid+1]);
}
for(i=ql;i<=qr;++i) if(!vs[id[i]]){
cir=0;ck(id[i],0);
if(cir){
x=to[cir];
chg=0;dfs(x,0);a=f[x][0];
chg=1;dfs(x,0);b=f[x][1];
if(a<=b) chg=0,dfs(x,0),gt(x,0,0);
else gt(x,1,0);
}else {dfs(id[i],0);gt(id[i],f[id[i]][1]<f[id[i]][0],0);}
}
for(i=ql;i<=qr;++i){
vs[id[i]]=cn[id[i]]=false;
if(!sid[id[i]]) swap(id[++tl],id[i]);
}
sol(l,mid,ql,tl);sol(mid+1,r,tl+1,qr);
}
int main(){
RI int i,x,y;
rd(n);rd(m);
if(n==2&&m==2){puts("3");return 0;}
for(i=1;i<=n;++i) {rd(d[i]);id[i]=i;v[i]=d[i];}
for(i=1;i<=n;++i) rd(w[i]);
for(i=1;i<=m;++i){rd(x);rd(y);lk(x,y,1);lk(y,x,0);}
sort(v+1,v+n+1);num=unique(v+1,v+n+1)-v-1;
sol(1,num,1,n);printf("%lld",ans);
return 0;
}