HDU 5293(Tree chain problem-树链剖分)

Tree chain problem

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 940    Accepted Submission(s): 248

Problem 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

Input

The input consists of several test cases. The first line of input gives the number of test cases T (T<=10).

For each tests:

First line two positive integers n, m.(1<=n,m<=100000)

The following (n - 1) lines contain 2 integers ai bi denoting an edge between vertices ai and bi (1≤ai,bi≤n),

Next m lines each three numbers u, v and val(1≤u,v≤n,0<val<1000), represent the two end points and the weight of a tree chain.

Output

For each tests:

A single integer, the maximum number of paths.

Sample Input

1
7 3
1 2
1 3
2 4
2 5
3 6
3 7
2 3 4
4 5 3
6 7 3

Sample Output

6

Hint

 Stack expansion program: #pragma comment(linker, "/STACK:1024000000,1024000000") 

Author

FZUACM

Source

2015 Multi-University Training Contest 1

Recommend

We have carefully selected several similar problems for you:  5421 5420 5419 5418 5417

考虑dp,dp[i]表示以i为根的子树的最优值,则

sum[i]=∑j∈son[i] 
d p[j]

容易想到有两种转移

  • (1) dp[i]=sum[i]
  • (2) dp[i]=value[p]+∑sum[k]?∑dp[k] (
     链p的lca是i,k是链上的节点)

    链上求和很容易想到树链剖分,复杂度O(Nlog2N)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<vector>
#include<iomanip>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (100000+10)
#define MAXM (200000+10)
#define MAXV (1000+10)
#define pb push_back
#define mp make_pair
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef int ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
struct Chain{
	int u,v,w;
	Chain(){}
	Chain(int _u,int _v,int _w):u(_u),v(_v),w(_w){}
};
vector<Chain> a[MAXN];
int n,m;
int edge[MAXM],Next[MAXM],Pre[MAXN],siz=1;
void addedge(int u,int v)
{
	edge[++siz]=v;
	Next[siz]=Pre[u];
	Pre[u]=siz;
}
void addedge2(int u,int v){addedge(u,v);addedge(v,u);}

bool vis[MAXN];
int cnt,id[MAXN];
int son[MAXN],dep[MAXN],sz[MAXN],top[MAXN],pre[MAXN],q[MAXN];
void build()
{
	MEM(vis) cnt=0; MEM(id)
	MEM(son) MEM(dep) MEM(sz) MEM(top) MEM(pre) MEM(q)
	int r=1;
	vis[dep[1]=q[1]=1]=1;
	For(i,r)
	{
		int u=q[i];
		Forp(u)
		{
			int v=edge[p];
			if (vis[v]) continue; else vis[v]=1;
			dep[ q[++r]=v ]=dep[u]+1;
			pre[v]=u;
		}
	}
	ForD(i,r) {
		sz[pre[q[i]]] += ++sz[q[i]];
		if (sz[son[pre[q[i]]]]<sz[q[i]] ) son[pre[q[i]]] = q[i];
	}
	For(i,r) {
		if (!top[q[i]])
			for(int x=q[i];x;x=son[x]) {
				top[x]=q[i];
				id[x]=++cnt;
			}
	}

}
int lca(int a,int b)
{
	while(1) {
		if (top[a]==top[b]) return dep[a]<=dep[b] ? a:b;
		if (dep[top[a]]<dep[top[b]]) swap(a,b);
		a=pre[top[a]];
	}
}

#define MEM2(a,i) memset(a,i,sizeof(a));
class SegmentTree
{
    ll a[MAXN*4],minv[MAXN*4],sumv[MAXN*4],maxv[MAXN*4],addv[MAXN*4],setv[MAXN*4];
    int n;
public:
    SegmentTree(){MEM(a) MEM(minv) MEM(sumv) MEM(maxv) MEM(addv) MEM2(setv,-1) }
    SegmentTree(int _n):n(_n){MEM(a) MEM(minv) MEM(sumv) MEM(maxv) MEM(addv) MEM2(setv,-1) }
    void mem(int _n)
    {
        n=_n;
        MEM(a) MEM(minv)  MEM(sumv) MEM(maxv) MEM(addv) MEM2(setv,-1)
    }  

    void maintain(int o,int L,int R)
    {

		sumv[o]=maxv[o]=minv[o]=0;
    	if (L<R) //只考虑左右子树
		{
			sumv[o]=sumv[Lson]+sumv[Rson];
			minv[o]=min(minv[Lson],minv[Rson]);
			maxv[o]=max(maxv[Lson],maxv[Rson]);
		} //只考虑add操作
		if (setv[o]>=0) sumv[o]=setv[o]*(R-L+1),minv[o]=maxv[o]=setv[o];

		minv[o]+=addv[o];maxv[o]+=addv[o];sumv[o]+=addv[o]*(R-L+1);
    }

	int y1,y2,v;
	void update(int o,int L,int R) //y1,y2,v
	{
		if (y1<=L&&R<=y2) {
			addv[o]+=v;
		}
		else{
			pushdown(o);
			int M=(R+L)>>1;
			if (y1<=M) update(Lson,L,M); else maintain(Lson,L,M);
			if (M< y2) update(Rson,M+1,R); else maintain(Rson,M+1,R);
		}

		maintain(o,L,R); 

	}
	void update2(int o,int L,int R)
	{
		if (y1<=L&&R<=y2) {
			setv[o]=v;addv[o]=0;
		}
		else{
			pushdown(o);
			int M=(R+L)>>1;
			if (y1<=M) update2(Lson,L,M); else maintain(Lson,L,M); //维护pushodown,再次maintain
			if (M< y2) update2(Rson,M+1,R); else maintain(Rson,M+1,R);
		}

		maintain(o,L,R);
	}

	void pushdown(int o)
	{
		if (setv[o]>=0)
		{
			setv[Lson]=setv[Rson]=setv[o];
			addv[Lson]=addv[Rson]=0;
			setv[o]=-1;
		}
		if (addv[o])
		{
			addv[Lson]+=addv[o];
			addv[Rson]+=addv[o];
			addv[o]=0;
		}
	}
	ll _min,_max,_sum; 

	void query2(int o,int L,int R,ll add)
	{
		if (setv[o]>=0)
		{
			_sum+=(setv[o]+addv[o]+add)*(min(R,y2)-max(L,y1)+1);
			_min=min(_min,setv[o]+addv[o]+add);
			_max=max(_max,setv[o]+addv[o]+add);
		} else if (y1<=L&&R<=y2)
		{
			_sum+=sumv[o]+add*(R-L+1);
			_min=min(_min,minv[o]+add);
			_max=max(_max,maxv[o]+add);
		} else {
		//	pushdown(o);
			int M=(L+R)>>1;
			if (y1<=M) query2(Lson,L,M,add+addv[o]);// else maintain(Lson,L,M);
			if (M< y2) query2(Rson,M+1,R,add+addv[o]);// else maintain(Rson,M+1,R);
		}
		//maintain(o,L,R);
	}

	void query(int o,int L,int R,ll add) //y1,y2
	{
		if (y1<=L&&R<=y2)
		{
			_sum+=sumv[o]+add*(R-L+1);
			_min=min(_min,minv[o]+add);
			_max=max(_max,maxv[o]+add);
		}
		else{
			int M=(R+L)>>1;
			if (y1<=M) query(Lson,L,M,add+addv[o]);
			if (M< y2) query(Rson,M+1,R,add+addv[o]);
		}
	}

	void add(int l,int r,ll v)
	{
		if (l>r) swap(l,r);
		y1=l,y2=r;this->v=v;
		update(1,1,n);
	}
	void set(int l,int r,ll v)
	{
		y1=l,y2=r;this->v=v;
		update2(1,1,n);
	}
	ll ask(int l,int r,int b=1)
	{
		if (l>r) swap(l,r);
		_sum=0,_min=INF,_max=-1;
		y1=l,y2=r;
		query2(1,1,n,0);
		switch(b)
		{
			case 1:return _sum;
			case 2:return _min;
			case 3:return _max;
			default:break;
		}
	}
	void print()
	{
		For(i,n)
			cout<<ask(i,i,1)<<' ';
		cout<<endl;

	}

    //先set后add
}S[2];   //sum & dp

int d[MAXN],s[MAXN];

ll Ask(int a,int b,int f)
{
	ll ans=0;
	while (top[a]^top[b]) {
		if (dep[top[a]]<dep[top[b]]) swap(a,b);
		ans+=S[f].ask(id[top[a]],id[a],1);
		a=pre[top[a]];
	}
	if (dep[a]>dep[b]) swap(a,b);
	ans+=S[f].ask(id[a],id[b],1);
	return ans;
}

void dfs(int u,int fa)
{
	Forp(u)
	{
		int v=edge[p];
		if (v==fa) continue;
		dfs(v,u);
		s[u]+=d[v];
	}
	d[u]=s[u];
	S[0].add(id[u],id[u],s[u]);
	int tot=a[u].size();
	Rep(j,tot)
	{
		Chain t = a[u][j];
		int fee=t.w;
		//
		d[u]=max(d[u],(int)(fee+Ask(t.u,t.v,0)-Ask(t.u,t.v,1)));
	}
	S[1].add(id[u],id[u],d[u]);  

}

int main()
{
//	freopen("hdu5293.in","r",stdin);

	int T;cin>>T;
	while(T--) {
		MEM(edge) MEM(Next) MEM(Pre) siz=1;
		MEM(d) MEM(s)
		For(i,n) a[i].clear();

		cin>>n>>m;
		S[0].mem(n);S[1].mem(n);
		For(i,n-1)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			addedge2(u,v);
		}
		build();

		For(i,m) {
			int u,v ,w;
			scanf("%d%d%d",&u,&v,&w);
			a[lca(u,v)].pb(Chain(u,v,w));
		}
		dfs(1,0);
		printf("%d\n",d[1]);
	}	

	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-23 01:25:50

HDU 5293(Tree chain problem-树链剖分)的相关文章

hdu 5293 Tree chain problem(树链剖分+树形dp)

题目链接:hdu 5293 Tree chain problem 维护dp[u], sum[u],dp[u]表示以u为根节点的子树的最优值.sum[u]表示以u节点的所有子节点的dp[v]之和.对于边a,b,w,在LCA(a,b)节点的时候进行考虑.dp[u] = min{dp[u], Sum(a,b) - Dp(a,b) + sum[u] | (ab链上的点,不包括u } #pragma comment(linker, "/STACK:1024000000,1024000000")

(中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

Problem 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

HDU 5293 Tree chain problem

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 565    Accepted Submission(s): 137 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n. Th

HDU 5293 TREE CHAIN PROBLEM LCT+树形DP

题解链接 代码链接 链接 Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 35    Accepted Submission(s): 8 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1

HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形dp, 对于每条链u,v,w,我们只在lca(u,v)的顶点上处理它 让dp[i]表示以i为根的指数的最大值,sum[i]表示dp[vi]的和(vi为i的儿子们) 则i点有两种决策,一种是不选以i为lca的链,则dp[i]=sum[i]. 另一种是选一条以i为lca的链,那么有转移方程:dp[i]=

HDU 3966Aragorn&#39;s Story(树链剖分)点权更新模板

Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4434    Accepted Submission(s): 1212 Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lor

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

HDU 2966 Aragorn&#39;s Story 树链剖分第一题 基础题

Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, the enemy has N camps out of his kingdom and M edges c

HDU 3966 Aragorn&#39;s Story 树链剖分

Link: http://acm.hdu.edu.cn/showproblem.php?pid=3966 这题注意要手动扩栈. 这题我交g++无限RE,即使手动扩栈了,但交C++就过了. 1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include &

HDU 3966 Aragorn&#39;s Story 树链剖分+BIT区间修改/单点询问

Aragorn's Story Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, the enemy has N camps out of his kingdom and M