hdu 4729 An Easy Problem for Elfness,函数式线段树

来源:互联网 发布:西门子840d攻丝编程 编辑:程序博客网 时间:2024/06/05 10:09
hdu 4729 An Easy Problem for Elfness,函数式线段树

13年成都网赛的题。
主要是问一个树上的某两个点间的路径,你可以对某些边增加一些流量,最多这个路径上能流过多少流量。
题目意思比较复杂(废话多),最大流量可以分成这几种情况:
1、增加一条边,剩下的费用用来增加这条边的流量,加上本来两点间的流量。
2、所有的费用用来建新边,加上本来的流量。
3、在本来的边上增加流量,求最大能通过流量。


最近怎么老根各种树过不去。
函数式线段树能够处理某些树上路径问题。

简单来说就是这样,以边权为下标建线段树。
想象每个点都有一个[1..cmax]的线段树,而且,每个点的树是从父节点的树插入一个之间的边的流量的点得到。

这样呢,我们可以用u、v、lca[u,v]的线段树来表示u到v路径的线段树。
u、v路径的线段树就是t[u]+t[v]-2*t[lca]。

现在问题就是找到最大的c,使得费用足够使得小于c的边都变成c。
线段树是个好东西,O(logn)可以搞定。
需要记录两个值,总权值v,总边数cnt。
如果(总共能添加的边流量val>=左区间的上界m*总边数cnt-总权值v),那就向右边递归,否则向左边。

具体看代码吧:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define NN 100010struct que{    int s,t,k,a,b,lca;    void init(int y,int u,int i,int o,int p){        s=y;t=u;k=i;a=o;b=p;    }}q[NN];vector<pair<int,int> > fi[NN];void addedge(int fr,int to,int val){    fi[fr].push_back(make_pair(to,val));}int root[NN],tott;struct segtree{    int ls,rs,l,r,v,cnt;    void init(int val=0){ls=rs=l=r=0;v=val;cnt=0;}}t[NN*20];void init_segtree(){    tott=0;    t[0].init();}int build(int l,int r){    int p=++tott;    t[p].l=l;t[p].r=r;t[p].v=t[p].cnt=0;    if (l==r){        t[p].ls=t[p].rs=0;return p;    }    int m=(l+r)>>1;    t[p].ls=build(l,m);    t[p].rs=build(m+1,r);    return p;}int insert(int pos,int num,int pas){    int p=++tott;    t[p]=t[pas];    t[p].v+=pos;    t[p].cnt+=num;    if (t[p].l==t[p].r) return p;    int m=(t[p].l+t[p].r)>>1;    if (pos<=m) t[p].ls=insert(pos,num,t[p].ls);    else t[p].rs=insert(pos,num,t[p].rs);    return p;}int query1(int s,int to,int lca,int tc=0,int tv=0){    return t[s].r*(tc+t[s].cnt+t[to].cnt-t[lca].cnt-t[lca].cnt)-(tv+t[s].v+t[to].v-t[lca].v-t[lca].v);}int queryc(int s,int to,int lca){    return t[s].cnt+t[to].cnt-t[lca].cnt-t[lca].cnt;}int queryv(int s,int to,int lca){    return t[s].v+t[to].v-t[lca].v-t[lca].v;}int query(int s,int to,int lca,int val,int tc,int tv){    if (t[s].l==t[s].r){        if (query1(s,to,lca,tc,tv)<=val) return t[s].l;        else return t[s].l-1;    }    int tmp,m=t[s].l+t[s].r>>1;    if ((tmp=query1(t[s].ls,t[to].ls,t[lca].ls,tc,tv))<=val){        return query(t[s].rs,t[to].rs,t[lca].rs,val,tc+queryc(t[s].ls,t[to].ls,t[lca].ls),tv+queryv(t[s].ls,t[to].ls,t[lca].ls));    }    else {        return query(t[s].ls,t[to].ls,t[lca].ls,val,tc,tv);    }}void dfs(int u,int fa,int val){    int i,v,sz;    if (u!=1){        root[u]=insert(val,1,root[fa]);    }    sz=fi[u].size();    for(i=0;i<sz;++i){        v=fi[u][i].first;        if (v!=fa){            dfs(v,u,fi[u][i].second);        }    }}vector<pair<int,int> > vec[NN];int set[NN],vis[NN];int dep[NN];int findset(int x){return x==set[x]?x:set[x]=findset(set[x]);}void init_lca(int n){    for(int i=1;i<=n;++i){vec[i].clear();set[i]=i;vis[i]=0;}}void tarjan(int u,int fa,int de){    int i;    dep[u]=de;    int v,sz=fi[u].size();    for(i=0;i<sz;++i){        v=fi[u][i].first;        if (v!=fa){            tarjan(v,u,de+1);            set[v]=u;        }    }    vis[u]=1;    sz=vec[u].size();    for(i=0;i<sz;++i){        v=vec[u][i].first;        if (vis[v]) q[vec[u][i].second].lca=findset(v);    }}int main(){    //freopen("4729in.txt","r",stdin);    int tcas,cas,n,m,cmax,a,b,c,s,t,k;    int i,val,tp,tmp,ans,lca;    scanf("%d",&tcas);    for(cas=1;cas<=tcas;++cas){        scanf("%d%d",&n,&m);        for(i=1;i<=n;++i)  fi[i].clear();        cmax=0;        for(i=1;i<n;++i){            scanf("%d%d%d",&a,&b,&c);            addedge(a,b,c);            addedge(b,a,c);            if (c>cmax) cmax=c;        }        init_lca(n);        for(i=1;i<=m;++i){            scanf("%d%d%d%d%d",&s,&t,&k,&a,&b);            q[i].init(s,t,k,a,b);            vec[s].push_back(make_pair(t,i));            vec[t].push_back(make_pair(s,i));        }        tarjan(1,-1,0);        init_segtree();        root[1]=build(1,cmax);        dfs(1,-1,0);        printf("Case #%d:\n",cas);        for(i=1;i<=m;++i){            a=q[i].a;b=q[i].b;k=q[i].k;s=q[i].s;t=q[i].t;lca=q[i].lca;            tmp=query(root[s],root[t],root[lca],0,0,0);            if (k>=a) ans=max(k/a+tmp,(k-a)/b+1+tmp);            else ans=0;            val=k/b;            tp=dep[s]+dep[t]-dep[lca]*2;            tmp=query1(root[s],root[t],root[lca]);            if (tmp<=val){                ans=max(ans,cmax+(val-tmp)/tp);            }            else {                ans=max(query(root[s],root[t],root[lca],val,0,0),ans);            }            printf("%d\n",ans);        }    }    return 0;}



0 0