L1保序回归问题-loj2470. 2018集训队互测Day 2有向图
传送门:loj2470
保序回归
详见2018国家集训队论文《浅谈保序回归问题》(高睿泉)。
定义如下:
这里仅仅谈一下针对此题(问题)的普遍解法,整体二分:
一些约定:
- 将序列中所有元素与取,与取称为序列向集合取整。
- 点集的均值为满足或最小的。
这里规定问题中。
存在引理:
证明有点繁琐,而且我没看懂QWQ,感性理解一下吧。
由此引理得到:
假设最优解不落在中,通过一组问题的最优解,就可以知道某一组原问题最优解中与的相对大小关系。
而对于问题,显然最优解一定在构成的集合中,所以在集合上做整体二分:二分到区间时,判断问题的最优解,根据,把点分别划分到和中。
小拓展:
-
一般偏序集上的问题,对应的问题可以看做简单的决策问题,而的限制相当于时,等价于最小权闭合子图问题,跑最小割解决。
-
的情况变成实数上二分即可。
题解
套用上述问题结论进行整体二分:
图仅仅是个基环树,网络流太逊了,考虑DP:
把图看做无向图,每条边分别表示的相对大小关系限制,设分别表示点取值时的子树的最小代价。
对于基环树:先把环找出来,强制一个点为0/1后DP转移即可。
p.s 记得记录转移时的后继状态(划分0/1用)
代码
#include<bits/stdc++.h>
#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;
}