码迷,mamicode.com
首页 > 其他好文 > 详细

dtoi2797 旅行商

时间:2020-02-02 21:52:52      阅读:79      评论:0      收藏:0      [点我收藏+]

标签:lca   name   cto   namespace   线段   code   最大值   ++   bsp   

题意:

     camp国有n座城市,由1,2,...,n编号。城市由n–1条双向道路相连。任意两个城市之间存在唯一的道路连通。有m个旅行商,第i个旅行商会从城市ai旅行到城市bi,贩卖ci件商品。已知第i个城市的居民最多购买wi件商品,bobo想知道旅行商们能够卖出商品数量的最大值。

     n,m<=20000。

题解:

     考虑暴力,对于每一个旅行商,将其路径上的所有点都连边,然后跑最大流就可以了。不过边数太多了,会TLE。

     那么这没有什么关系,我们可以树剖+线段树,将每个旅行商连向他们所对应的节点,容量为INF即可。当然每个线段树节点也都要向各自的城市连边。

     这样的话,边数就优化成了m*logn*logn,再跑最大流,可以通过这道题。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
#include<queue>
using namespace std;
const int INF=2e9;
typedef struct{
    int w,zjds,xzd,dep,dfn,twz;
}P;
P p[20002];
int n,m,fa[22][20002],d[100005],cur[100005],cnt,hh=80000,s=100001,t=100002,df[20002];
vector<int>g[20002];
struct Edge{
    int from,to,cap,flow;
    Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
vector<int>c[100005];
vector<Edge>edges;
void add(int u,int v,int w){
    edges.push_back(Edge(u,v,w,0));
    edges.push_back(Edge(v,u,0,0));
    c[u].push_back(edges.size()-2);
    c[v].push_back(edges.size()-1); 
}
bool bfs(int s){
    queue<int>q;memset(d,-1,sizeof(d));
    q.push(s);d[s]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for (int i=0;i<c[u].size();i++)
        {
            Edge e=edges[c[u][i]];
            if (e.cap>e.flow && d[e.to]==-1)
            {
                q.push(e.to);d[e.to]=d[u]+1;
                if (e.to==t)return true;
            }
        }
    }
    return false;
}
int dfs(int x,int a){
    if (x==t)return a;
    int flow=0,f;
    for (int& i=cur[x];i<c[x].size();i++)
    {
        Edge& e=edges[c[x][i]];
        if (e.cap>e.flow && d[x]+1==d[e.to] && (f=dfs(e.to,min(a,e.cap-e.flow)))>0)
        {
            flow+=f;a-=f;
            e.flow+=f;edges[c[x][i]^1].flow-=f;
        }
        if (!a)break;
    }
    return flow;
}
void dfs1(int x,int faa,int deep){
    int Max=0,maxn=-1;p[x].zjds=1;fa[0][x]=faa;p[x].dep=deep;
    for (int i=0;i<g[x].size();i++)
    if (g[x][i]!=faa)
    {
        dfs1(g[x][i],x,deep+1);p[x].zjds+=p[g[x][i]].zjds;
        if (p[g[x][i]].zjds>Max)
        {
            Max=p[g[x][i]].zjds;maxn=g[x][i];
        }
    }
    p[x].xzd=maxn;
}
void dfs2(int x,int fa){
    p[x].dfn=++cnt;if (p[fa].xzd==x)p[x].twz=p[fa].twz;else p[x].twz=x;
    df[cnt]=x;
    if (p[x].xzd!=-1)dfs2(p[x].xzd,x);
    for (int i=0;i<g[x].size();i++)
    if (g[x][i]!=fa && g[x][i]!=p[x].xzd)dfs2(g[x][i],x);
}
int lca(int x,int y){
    if (p[x].dep<p[y].dep)swap(x,y);
    int k=p[x].dep-p[y].dep;
    for (int i=0;i<=20;i++)
    if (k&(1<<i))x=fa[i][x];
    if (x==y)return x;
    for (int i=20;i>=0;i--)
    if (fa[i][x]!=fa[i][y])
    {
        x=fa[i][x];y=fa[i][y];
    }
    return fa[0][x];
}
void build(int root,int begin,int end){
    if (begin==end)
    {
        add(s,root,p[df[begin]].w);return;
    }
    int mid=(begin+end)/2;
    build(root*2,begin,mid);build(root*2+1,mid+1,end);
    add(root*2,root,INF);add(root*2+1,root,INF);
}
void gengxin(int root,int begin,int end,int begin2,int end2,int wz){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        add(root,hh+wz,INF);return;
    }
    int mid=(begin+end)/2;
    gengxin(root*2,begin,mid,begin2,end2,wz);gengxin(root*2+1,mid+1,end,begin2,end2,wz);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)scanf("%d",&p[i].w);
    for (int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);g[x].push_back(y);g[y].push_back(x);
    }
    dfs1(1,0,1);dfs2(1,0);
    for (int i=1;i<=20;i++)
    for (int j=1;j<=n;j++)
    fa[i][j]=fa[i-1][fa[i-1][j]];
    build(1,1,n);
    for (int i=1;i<=m;i++)
    {
        int u,v,lc,h;
        scanf("%d%d%d",&u,&v,&h);
        lc=lca(u,v);
        while(p[u].dep>=p[lc].dep)
        {
            if (p[p[u].twz].dep<p[lc].dep)gengxin(1,1,n,p[lc].dfn,p[u].dfn,i);
            else
            {
                gengxin(1,1,n,p[p[u].twz].dfn,p[u].dfn,i);
            }
            u=fa[0][p[u].twz];
        }
        while(p[v].dep>=p[lc].dep)
        {
            if (p[p[v].twz].dep<p[lc].dep)gengxin(1,1,n,p[lc].dfn,p[v].dfn,i);
            else
            {
                gengxin(1,1,n,p[p[v].twz].dfn,p[v].dfn,i);
            }
            v=fa[0][p[v].twz];
        }
        add(hh+i,t,h);
    }
    int ans=0;
    while(bfs(s)){memset(cur,0,sizeof(cur));ans+=dfs(s,INF);}
    printf("%d\n",ans);
    return 0;
}

dtoi2797 旅行商

标签:lca   name   cto   namespace   线段   code   最大值   ++   bsp   

原文地址:https://www.cnblogs.com/1124828077ccj/p/12253699.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!