HDU 5293 Tree chain problem [树链剖分+线段树+树形DP]

Description

Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n. 
There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices. 
Find out the maximum sum of the weight Coco can pick 


题意:给出N个点的树,M条树链,树链有权,问在取出的树链互不相交的情况下,权值和最大是多少。

解法:可以这么考虑,若某点作为一个点对X,Y的LCA,那么如果取了这条链,其子树的解最大是多少呢?

设DP[x]表示以x为根的子树中,取完以此点为lca的链后能取得的最大值。那么可以知道,取了某条链后(此链的lca为x)其能获得的最大值为 Σ DP[{son}] +W 其中{son}是此链的儿子集合(不包括链本身),那么我们可以dfs处理,dfs到某一个点x,处理以x点为lca的所有链,计算出取了每条链后能获得的值的最大值,将其赋值给dp[X]。

那么怎么求Σ DP[{son}] ? 我们可以这么处理:每次求出一个dp[X],将 -dp[X] 加到X点的VAL[],+dp[X]加到X点的父亲的VAL[],那么 Σ VAL[链上的点] 就是所求的答案。很明显,求链上点权和 可以用树链剖分+线段树写,复杂度为N*logN*logN。(实际上,因为此题没有修改,可以DFS序+树状数组快速处理 O(N*logN))

代码:(ZKW线段树 1200+MS)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#pragma comment(linker, "/STACK:1024000000,1024000000")
template 
bool scanff(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair pii;

#define NN 100100

struct node{
    int x,y,w;
}a[NN];
vector q[NN];
int son[NN],sz[NN],top[NN],pos[NN],dep[NN],f[NN][20],pn;
int ptx[NN],lnum,dp[NN];
int n,qn;
struct edge{
    int v,next;
    edge(){}
    edge(int v,int next){
        this->v=v;
        this->next=next;
    }
}ed[NN*2];
void addline(int x,int y){
    ed[lnum]=edge(y,ptx[x]);
    ptx[x]=lnum++;
}
void init(int n){
    pn=lnum=0;
    rep(i,1,n)ptx[i]=-1;
    rep(i,1,n)q[i].clear();
}
//tree chain divide
int getson(int x,int fa){
    int val=0;
    son[x]=0;
    sz[x]=1;
    f[x][0]=fa;
    dep[x]=dep[fa]+1;
    gson(i,x){
        int y=ed[i].v;
        if(y==fa)continue;
        sz[x]+=getson(y,x);
        if(sz[y]>val){
            val=sz[y];
            son[x]=y;
        }
    }
    return sz[x];
}
void getchain(int r,int x,int fa){
    top[x]=r;
    pos[x]=++pn;
    if(son[x])getchain(r,son[x],x);
    gson(i,x){
        int y=ed[i].v;
        if(y==fa||y==son[x])continue;
        getchain(y,y,x);
    }
}
int lca(int x,int y){
    if(dep[x]=dep[y])x=f[x][i];
    if(x==y)return x;
    drep(i,16,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}
//segment tree
int m,val[NN*4];
void build(int n){
    for(m=1;m>=1,r>>=1){
        if(~l&1)sum+=val[l^1];
        if(r&1) sum+=val[r^1];
    }
    return sum;
}
inline void update(int pos,int v){
    for(pos=pos+m;pos;pos>>=1)val[pos]+=v;
}
//solve
void calc(int z){
    int sz=q[z].size()-1;
    rep(i,0,sz){
        int x=q[z][i].x;
        int y=q[z][i].y;
        int w=q[z][i].w;
        while(top[x]!=top[y]){
            if(dep[top[x]]dep[y])swap(x,y);
        w+=query(pos[x],pos[y]);
        dp[z]=max(w,dp[x]);
    }
    update(pos[z],-dp[z]);
    if(f[z][0])update(pos[f[z][0]],dp[z]);
}
void solve(int x,int fa){
    dp[x]=0;
    gson(i,x){
        int y=ed[i].v;
        if(y==fa)continue;
        solve(y,x);
        dp[x]+=dp[y];
    }
    calc(x);
}
int main(){
    tdata{
        scanff(n);scanff(qn);
        init(n);
        build(n);
        rep(i,1,n-1){
            int x;scanff(x);
            int y;scanff(y);
            addline(x,y);
            addline(y,x);
        }
        getson(1,0);
        getchain(1,1,0);
        rep(k,1,16)
        rep(i,1,n)f[i][k]=f[f[i][k-1]][k-1];
        rep(i,1,qn){
            scanff(a[i].x);
            scanff(a[i].y);
            scanff(a[i].w);
            q[lca(a[i].x,a[i].y)].pb(a[i]);
        }
        solve(1,0);
        printf("%d\n",dp[1]);
    }
}



你可能感兴趣的:(动态规划--树形DP,数据结构--树链剖分,数据结构--线段树)