HDU5293 : Tree chain problem

Claris發表於2017-10-20

問題即:選擇價值和最多的鏈,使得每個點最多被一條鏈覆蓋。

那麼考慮其對偶問題:選擇最少的點(每個點可以重複選),使得每條鏈上選了至少$w_i$個點。

那麼將鏈按照LCA的深度從大到小排序,每次若發現點數不夠,則在LCA處補充點,樹鏈剖分+線段樹維護。

時間複雜度$O(m\log^2n)$。

 

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100010,M=262150;
int Case,cas,n,m,q,i,op,x,y,z;
int g[N],v[N<<1],nxt[N<<1],ed;
int size[N],son[N],f[N],d[N],st[N],top[N],dfn;
int val[M];
int ans;
struct E{int x,y,z,w;}e[N];
inline bool cmp(const E&a,const E&b){return d[a.z]<d[b.z];}
inline void addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
    size[x]=1;
    for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
        f[v[i]]=x,d[v[i]]=d[x]+1;
        dfs(v[i]),size[x]+=size[v[i]];
        if(size[v[i]]>size[son[x]])son[x]=v[i];
    }
}
void dfs2(int x,int y){
    st[x]=++dfn;top[x]=y;
    if(son[x])dfs2(son[x],y);
    for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
}
void build(int x,int a,int b){
    val[x]=0;
    if(a==b)return;
    int mid=(a+b)>>1;
    build(x<<1,a,mid),build(x<<1|1,mid+1,b);
}
void change(int x,int a,int b,int c,int p){
    val[x]+=p;
    if(a==b)return;
    int mid=(a+b)>>1;
    if(c<=mid)change(x<<1,a,mid,c,p);
    else change(x<<1|1,mid+1,b,c,p);
}
int ask(int x,int a,int b,int c,int d){
    if(c<=a&&b<=d)return val[x];
    int mid=(a+b)>>1,t=0;
    if(c<=mid)t=ask(x<<1,a,mid,c,d);
    if(d>mid)t+=ask(x<<1|1,mid+1,b,c,d);
    return t;
}
inline int lca(int x,int y){
    for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
    return d[x]<d[y]?x:y;
}
inline int chain(int x,int y){
    int t=0;
    for(;top[x]!=top[y];x=f[top[x]]){
        if(d[top[x]]<d[top[y]])swap(x,y);
        t+=ask(1,1,n,st[top[x]],st[x]);
    }
    if(d[x]<d[y])swap(x,y);
    t+=ask(1,1,n,st[y],st[x]);
    return t;
}
inline void gao(int x,int y,int z,int w){
    int t=chain(x,y);
    if(t>=w)return;
    w-=t;
    ans+=w;
    change(1,1,n,st[z],w);
}
int main(){
    scanf("%d",&Case);
    while(Case--){
        scanf("%d%d",&n,&m);
        for(i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            addedge(x,y),addedge(y,x);
        }
        dfs(1);
        dfs2(1,1);
        build(1,1,n);
        for(i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&e[i].w);
            e[i].x=x,e[i].y=y;
            e[i].z=lca(x,y);
        }
        sort(e+1,e+m+1,cmp);
        for(i=m;i;i--)gao(e[i].x,e[i].y,e[i].z,e[i].w);
        printf("%d\n",ans);
        for(i=0;i<=n;i++)g[i]=size[i]=son[i]=f[i]=d[i]=st[i]=top[i]=0;
        ed=dfn=ans=0;
    }
}

  

相關文章