• 旅行商(sale)


    旅行商(sale)

    题目描述

     

     

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

     

    输入

     

     

    输入文件sale.in。

    第一行,包含2个整数n和m。

    第二行,包含n个整数w1,w2,…,wn。

    接下来n–1行中的第i行包含2个整数ui,vi代表城市ui和vi之间有一条道路。

    最后的m行中的第i行包含3个整数ai,bi,ci。

     

    输出

     

     

    输出文件sale.out。

    1个整数,代表卖出商品数量的最大值。

     

    样例输入

    4 2
    0 1 2 2
    1 4
    2 4
    3 4
    1 2 2
    1 3 3

    样例输出

    5
    

    提示

     

     

    【数据范围和约定】

    数据点

    n,m的范围

    其他

    1

    ≤500

    1≤ui,vi,ai,bi≤n

    0≤wi,ci≤105

    2

    3

    4

    ≤5,000

    5

    6

    7

    ≤2×104

    8

    9

    10

     

    solution

    树剖,转化为区间问题

    先暴力建图

    每个旅行商向他要去的所有城市连边,发现边数n^2

    考虑用线段树优化建图,城市开成线段树,旅行商向节点连边

    然后就可以啦

    好裸的题

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define maxn 20005
    #define N 400005
    #define inf 1e9
    using namespace std;
    int n,m,w[maxn],dfn[maxn],sc,son[maxn],fa[maxn],top[maxn],size[maxn];
    int deep[maxn],t1,t2,t3,tot=1,a,b,c,dy[maxn],li,ri,cnt,S,T,ans;
    int head[N],cur[N],flag[N],d[N];
    queue<int>q;
    vector<int>G[maxn];
    struct node{
        int v,nex,cap;
    }e[N*20];
    struct no{
        int l,r,x;
    }tree[maxn*4];
    void lj(int t1,int t2,int t3){
        e[++tot].v=t2;e[tot].cap=t3;e[tot].nex=head[t1];head[t1]=tot;
        e[++tot].v=t1;e[tot].cap=0;e[tot].nex=head[t2];head[t2]=tot;
    }
    void dfs1(int k,int fath){
        fa[k]=fath;deep[k]=deep[fath]+1;
        int sz=0,gp=-1;
        for(int i=0;i<G[k].size();i++){
            int v=G[k][i];
            if(v!=fath){
                dfs1(v,k);
                sz+=size[v];
                if(gp==-1)gp=v;
                else if(size[v]>size[gp])gp=v;
            }
        }
        size[k]=sz+1;son[k]=gp;
    }
    void dfs2(int k){
        dfn[k]=++sc;dy[sc]=k;
        if(son[k]!=-1)top[son[k]]=top[k],dfs2(son[k]);
        for(int i=0;i<G[k].size();i++){
            int v=G[k][i];
            if(v!=fa[k]&&v!=son[k]){
                top[v]=v;dfs2(v);
            }
        }
    }
    void wh(int k){
        tree[k].x=tree[k*2].x+tree[k*2+1].x;
    }
    void build(int k,int L,int R){
        tree[k].l=L,tree[k].r=R;
        if(L==R){
            tree[k].x=w[dy[L]];lj(k,T,w[dy[L]]);
            cnt=max(cnt,k);
            return;
        }
        int mid=L+R>>1;
        build(k*2,L,mid);build(k*2+1,mid+1,R);
        lj(k,k*2,tree[k*2].x);lj(k,k*2+1,tree[k*2+1].x);
        wh(k);
    }
    void fsy(int k,int id){
        if(tree[k].l>=li&&tree[k].r<=ri){
            lj(id,k,inf);return;
        }
        int mid=tree[k].l+tree[k].r>>1;
        if(li<=mid)fsy(k*2,id);
        if(ri>mid)fsy(k*2+1,id);
    }
    bool BFS(){
        for(int i=1;i<=T;i++)d[i]=inf;
        d[S]=0;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();
            cur[x]=head[x];
            for(int i=head[x];i;i=e[i].nex){
                if(d[e[i].v]>d[x]+1&&e[i].cap>0){
                    d[e[i].v]=d[x]+1;
                    if(!flag[e[i].v]){
                        flag[e[i].v]=1;q.push(e[i].v);
                    }
                }
            }
            flag[x]=0;
        }
        return d[T]!=inf;
    }
    int lian(int k,int a){
        if(k==T||!a)return a;
        int f,flow=0;
        for(int &i=cur[k];i;i=e[i].nex){
            if(d[e[i].v]==d[k]+1&&(f=lian(e[i].v,min(e[i].cap,a)))>0){
                e[i].cap-=f;e[i^1].cap+=f;
                a-=f;flow+=f;
                if(!a)break;
            }
        }
        return flow;
    }
    int main()
    {
        cin>>n>>m;S=400001,T=S+1;
        for(int i=1;i<=n;i++)scanf("%d",&w[i]);
        for(int i=1;i<n;i++){
            scanf("%d%d",&t1,&t2);
            G[t1].push_back(t2);G[t2].push_back(t1);
        }
        dfs1(1,0);top[1]=1;dfs2(1);
        build(1,1,n);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            int t1=top[a],t2=top[b];
            while(t1!=t2){
                if(deep[t1]<deep[t2])swap(t1,t2),swap(a,b);
                li=dfn[t1],ri=dfn[a];
                fsy(1,cnt+i);
                a=fa[t1];t1=top[a];
            }
            if(deep[a]<deep[b])swap(a,b);
            li=dfn[b],ri=dfn[a];
            fsy(1,cnt+i);
            lj(S,cnt+i,c);
        }
        while(BFS())ans+=lian(S,inf);
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    20170411linux常用命令
    20170411oracle常用命令
    20170411-oracle 查询指定节点下的所有子节点包括直到叶子节点
    20170329oracle安装教程
    20170329plsql连接oracle
    20170329001怎么让plsql窗口列表保持
    Eclispse 换主题、皮肤、配色,换黑色主题护眼
    zbb20170303使用ssh一直找不到session,报错not found session in current thread
    zbb20170303_ant_build.xml详解
    hdu Farm Irrigation
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358871.html
Copyright © 2020-2023  润新知