暑假集训8.10-网络流套树剖套线段树

题目:dtoj2797旅行商

   其实就是裸的网络流套树剖套线段树其实代码不难码

emmmmmm我决定草率的直接上代码,这可能是一条无营养的博客....

#include<bits/stdc++.h>
#define _(d) while(d(isdigit(ch=getchar())))
#define il inline
using namespace std;
const int N=2e5+5,M=4e6+5,inf=2e9;int n,m,ne[M],to[M],head[N],v[M],d[N],val[N],s,t,ans;
int ne1[N<<1],to1[N<<1],head1[N],fa[N],sz[N],son[N],d1[N],idx[N],tot,num[N],top[N],cnt;queue<int> q;
int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;return f*x;}
il void insert(int x,int y,int z){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;v[cnt]=z;}
il void add(int u,int v,int w){insert(u,v,w);insert(v,u,0);}
il void ins(int x,int y){ne1[++cnt]=head1[x];head1[x]=cnt;to1[cnt]=y;}
il bool bfs(){
    memset(d,-1,sizeof(d));q.push(s);d[s]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=ne[i]){
            if(!v[i]||d[to[i]]!=-1)continue;
            q.push(to[i]);d[to[i]]=d[x]+1;
        }
    }
    return d[t]!=-1;
}
int dfs(int x,int f){
    if(x==t)return f;int w,used=0;
    for(int i=head[x];i;i=ne[i]){
        if(d[x]+1!=d[to[i]]||(!v[i]))continue;
        w=f-used;w=dfs(to[i],min(w,v[i]));
        v[i]-=w;v[i^1]+=w;used+=w;if(used==f)return used;
    }
    if(!used)d[x]=-1;return used;
}
il void dinic(){while(bfs()){ans+=dfs(s,inf);}}
void dfs1(int x){
    sz[x]=1;int maxn=-1;
    for(int i=head1[x];i;i=ne1[i]){
        if(to1[i]==fa[x])continue;
        d1[to1[i]]=d1[x]+1;fa[to1[i]]=x;dfs1(to1[i]);
        sz[x]+=sz[to1[i]];if(sz[to1[i]]>maxn)maxn=sz[to1[i]],son[x]=to1[i];
    }
}
void dfs2(int x,int rt){
    top[x]=rt;idx[x]=++tot;num[tot]=x;
    if(!son[x])return;dfs2(son[x],rt);
    for(int i=head1[x];i;i=ne1[i]){
        if(idx[to1[i]])continue;dfs2(to1[i],to1[i]);
    }
}
void build(int x,int l,int r){
    if(l==r){add(m+x,t,val[num[l]]);return;}
    int mid=(l+r)>>1;build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    add(m+x,m+(x<<1),inf);add(m+x,m+(x<<1|1),inf);
}
void intervallink(int x,int l,int r,int ql,int qr,int k){
    if(ql<=l&&r<=qr){add(k,m+x,inf);return;}
    int mid=(l+r)>>1;
    if(ql<=mid)intervallink(x<<1,l,mid,ql,qr,k);
    if(mid<qr)intervallink(x<<1|1,mid+1,r,ql,qr,k);
}
il void Treelink(int x,int y,int k){
    while(top[x]!=top[y]){
        if(d1[top[x]]<d1[top[y]])swap(x,y);
        intervallink(1,1,n,idx[top[x]],idx[x],k);x=fa[top[x]];
    }
    if(d1[x]>d1[y])swap(x,y);intervallink(1,1,n,idx[x],idx[y],k);
}
int main()
{
  n=read();m=read();t=m+4*n+1;for(int i=1;i<=n;i++)val[i]=read();
  for(int i=1;i<n;i++){int u,v;u=read();v=read();ins(u,v);ins(v,u);}cnt=1;
  d1[1]=1;dfs1(1);dfs2(1,1);build(1,1,n);
  for(int i=1;i<=m;i++){int a,b,c;a=read();b=read();c=read();add(s,i,c);Treelink(a,b,i);}
  dinic();printf("%d\n",ans);
  return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Jessie-/p/9463494.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值