hdu6611
做法一: 用主席树优化建图,用dp优化第一次dij算法
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> pii; struct MCMF{ static const int maxn=2005*20*2,maxm=2+3*2005+2005*20*4; struct star{int v,nex,c,w;} edge[maxm<<1]; int head[maxn],cnt,n; int pre[maxn],dist[maxn],h[maxn];// h -> 势能函数 void ini(int point){ cnt=-1;n=point; for(int i=0;i<=n;i++) head[i]=-1,h[i]=0; } void add_edge(int u, int v, int c, int w){ // cout<<" "<<u<<" "<<v<<" "<<c<<" "<<w<<endl; edge[++cnt]=star{v,head[u],c, w}; head[u]=cnt; edge[++cnt]=star{u,head[v],0,-w}; head[v]=cnt; } void minCostMaxFlow(int s, int t,int&flow,int&cost){//dij flow=cost=0; while(true){ for(int i=0;i<=n;i++) dist[i]=2e9; dist[s]=0; priority_queue<pii,vector<pii>,greater<pii>>que; que.push(pii(dist[s],s)); while(!que.empty()){ int u=que.top().second,dis=que.top().first; que.pop(); if (dist[u]!=dis) continue; for(int i=head[u];~i;i=edge[i].nex){ int v=edge[i].v,c=edge[i].c,w=edge[i].w; if(c>0&&dist[v]>dist[u]+w+h[u]-h[v]){ dist[v]=dist[u]+w+h[u]-h[v]; // assert(dist[v]>=0); pre[v]=i; que.push(pii(dist[v],v)); } } } if(dist[t]==2e9) break; for(int i=0;i<=n;i++) h[i]+=dist[i];// d[i]=dist[i]+h[i]-h[s]=dist[i]+h[i] int addf=2e9; for(int x=t;x!=s;x=edge[pre[x]^1].v) addf=min(addf,edge[pre[x]].c); for(int x=t;x!=s;x=edge[pre[x]^1].v) { edge[pre[x]].c-=addf; edge[pre[x]^1].c+=addf; } flow+=addf; cost+=h[t]*addf; } } }g; int a[2005],n,k,s,t; //主席树优化建图 dp优化dij #define ml ((l+r)>>1) #define mr (ml+1) const int maxn = 2005; int ls[maxn*20],rs[maxn*20],tot,rt[maxn];//update用了几次,就要乘以多少 void update(int pre,int&u,int l,int r,int pos,int dst){//把u按照pre复制,然后更新pos u=++tot; ls[u]=ls[pre];rs[u]=rs[pre]; if(pre!=0) { g.add_edge((pre+n+2)<<1|1,(u+n+2)<<1,k,0); // k flow g.h[(u+n+2)<<1]=g.h[(u+n+2)<<1|1]=min(g.h[(pre+n+2)<<1],g.h[dst<<1|1]); } else g.h[(u+n+2)<<1]=g.h[(u+n+2)<<1|1]=g.h[dst<<1|1]; g.add_edge(dst<<1|1,(u+n+2)<<1,k,0);// k flow g.add_edge((u+n+2)<<1,(u+n+2)<<1|1,k,0);// k flow if(l==r)return; if(pos<=ml) update(ls[pre],ls[u],l,ml,pos,dst); else update(rs[pre],rs[u],mr,r,pos,dst); } void query(int u,int l,int r,int pos,int dst){ if(r<=pos){ if(u!=0) { g.add_edge((u+n+2)<<1|1,dst<<1,k,0);// k flow g.h[dst<<1]=min(g.h[dst<<1],g.h[(u+n+2)<<1]); } g.h[dst<<1|1]=g.h[dst<<1]-pos; return; } if(l>pos) return; query(ls[u],l,ml,pos,dst); query(rs[u],mr,r,pos,dst); } void build_graph(){ tot=0; g.ini(n*20*2); s=n+1,t=n+2; g.add_edge(s<<1,s<<1|1,k,0);// k flow g.h[s<<1]=g.h[s<<1|1]=0; int mim=0; for(int i=1;i<=n;i++) mim=max(mim,a[i]); for(int i=1;i<=n;i++) { g.add_edge(s<<1|1,i<<1,k,0);// k flow g.add_edge(i<<1,i<<1|1,1,-a[i]);// 1 flow g.add_edge(i<<1|1,t<<1,k,0);// k flow query(rt[i-1],1,mim,a[i],i); update(rt[i-1],rt[i],1,mim,a[i],i); } g.add_edge(t<<1,t<<1|1,k,0);// k flow g.h[t<<1]=g.h[t<<1|1]=g.h[(rt[n]+n+2)<<1]; } /////////////////////////// //究极读入挂 inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ char ch=nc();int sum=0; while(!(ch>='0'&&ch<='9'))ch=nc(); while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc(); return sum; } int main(){ // freopen("/Users/s/Downloads/2019HDOJ多校3_UESTC/data/1009/multi.in","r",stdin); int ti=read(); while(ti--){ n=read();k=read(); for(int i=1;i<=n;i++) a[i]=read(); build_graph(); int flow,cost; g.minCostMaxFlow(s<<1,t<<1|1,flow,cost); printf("%d\n",-cost); //cout<<-cost<<endl; } }
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> pii; struct MCMF{ static const int maxn=2005*20*2,maxm=2+3*2005+2005*20*4; struct star{int v,nex,c,w;} edge[maxm<<1]; int head[maxn],cnt,n; int pre[maxn],dist[maxn],h[maxn];// h -> 势能函数 void ini(int point){ cnt=-1;n=point; for(int i=0;i<=n;++i) head[i]=-1,h[i]=0; } void add_edge(int u, int v, int c, int w){ // cout<<" "<<u<<" "<<v<<" "<<c<<" "<<w<<endl; edge[++cnt]=star{v,head[u],c, w}; head[u]=cnt; edge[++cnt]=star{u,head[v],0,-w}; head[v]=cnt; } void minCostMaxFlow_dij(int s, int t,int&flow,int&cost){//dij flow=cost=0; while(true){ for(int i=0;i<=n;++i) dist[i]=2e9; dist[s]=0; priority_queue<pii,vector<pii>,greater<pii>>que; que.push(pii(dist[s],s)); while(!que.empty()){ int u=que.top().second,dis=que.top().first; que.pop(); if (dist[u]!=dis) continue; for(int i=head[u];~i;i=edge[i].nex){ int v=edge[i].v,c=edge[i].c,w=edge[i].w; if(c>0&&dist[v]>dist[u]+w+h[u]-h[v]){ dist[v]=dist[u]+w+h[u]-h[v]; // assert(dist[v]>=0); pre[v]=i; que.push(pii(dist[v],v)); } } } if(dist[t]==2e9) break; for(int i=0;i<=n;++i) h[i]+=dist[i];// d[i]=dist[i]+h[i]-h[s]=dist[i]+h[i] int addf=2e9; for(int x=t;x!=s;x=edge[pre[x]^1].v) addf=min(addf,edge[pre[x]].c); for(int x=t;x!=s;x=edge[pre[x]^1].v) { edge[pre[x]].c-=addf; edge[pre[x]^1].c+=addf; } flow+=addf; cost+=h[t]*addf; } } void minCostMaxFlow(int s, int t,int&flow,int&cost){//spfa 用来先负权图处理 for(int i=0;i<=n;++i) dist[i]=2e9; dist[s]=0; queue<pii>que; que.push(pii(dist[s],s)); while(!que.empty()){ int u=que.front().second,dis=que.front().first; que.pop(); if (dist[u]!=dis) continue; for(int i=head[u];~i;i=edge[i].nex){ int v=edge[i].v,c=edge[i].c,w=edge[i].w; if(c>0&&dist[v]>dist[u]+w){ dist[v]=dist[u]+w; pre[v]=i; que.push(pii(dist[v],v)); } } } if(dist[t]==2e9) return; for(int i=0;i<=n;++i) h[i]=dist[i];// d[i]=dist[i]+h[i]-h[s]=dist[i]+h[i] int addf=2e9; for(int x=t;x!=s;x=edge[pre[x]^1].v) addf=min(addf,edge[pre[x]].c); for(int x=t;x!=s;x=edge[pre[x]^1].v) { edge[pre[x]].c-=addf; edge[pre[x]^1].c+=addf; } int oldh=h[t]; minCostMaxFlow_dij(s,t,flow,cost); flow+=addf; cost+=oldh*addf; } }g; int a[2005],n,k,s,t; //主席树优化建图 dp优化dij #define ml ((l+r)>>1) #define mr (ml+1) const int maxn = 2005; int ls[maxn*20],rs[maxn*20],tot,rt[maxn];//update用了几次,就要乘以多少 void update(int pre,int&u,int l,int r,int pos,int dst){//把u按照pre复制,然后更新pos u=++tot; ls[u]=ls[pre];rs[u]=rs[pre]; if(pre!=0) g.add_edge((pre+n+2)<<1|1,(u+n+2)<<1,k,0); // k flow g.add_edge(dst<<1|1,(u+n+2)<<1,k,0);// k flow g.add_edge((u+n+2)<<1,(u+n+2)<<1|1,k,0);// k flow if(l==r)return; if(pos<=ml) update(ls[pre],ls[u],l,ml,pos,dst); else update(rs[pre],rs[u],mr,r,pos,dst); } void query(int u,int l,int r,int pos,int dst){ if(r<=pos){ if(u!=0)g.add_edge((u+n+2)<<1|1,dst<<1,k,0);// k flow return; } if(l>pos) return; query(ls[u],l,ml,pos,dst); query(rs[u],mr,r,pos,dst); } void build_graph(){ tot=0; g.ini(n*20*2); s=n+1,t=n+2; g.add_edge(s<<1,s<<1|1,k,0);// k flow int mim=0; for(int i=1;i<=n;++i) mim=max(mim,a[i]); for(int i=1;i<=n;++i) { g.add_edge(s<<1|1,i<<1,k,0);// k flow g.add_edge(i<<1,i<<1|1,1,-a[i]);// 1 flow g.add_edge(i<<1|1,t<<1,k,0);// k flow query(rt[i-1],1,mim,a[i],i); update(rt[i-1],rt[i],1,mim,a[i],i); } g.add_edge(t<<1,t<<1|1,k,0);// k flow } /////////////////////////// //究极读入挂 inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ char ch=nc();int sum=0; while(!(ch>='0'&&ch<='9'))ch=nc(); while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc(); return sum; } int main(){ // freopen("/Users/s/Downloads/2019HDOJ多校3_UESTC/data/1009/multi.in","r",stdin); int ti=read(); while(ti--){ n=read();k=read(); for(int i=1;i<=n;++i) a[i]=read(); build_graph(); int flow,cost; g.minCostMaxFlow(s<<1,t<<1|1,flow,cost); printf("%d\n",-cost); } }