2016多校训练Contest4: 1007 Treasure hdu5770

8 篇文章 0 订阅
5 篇文章 0 订阅

Problem Description
?? has got a treasure map,the treasure map consists of N nodes,there are N-1 bidirectional roads, Each of them connects a pair of nodes,the N nodes are all connected by the N-1 bidirectional roads.?? can travel through the roads.
There are M treasures in some node. Each treasure has a value, treasures are put into boxs,each treasure corresponds to a box and each box corresponds to a key which is also in some node. Now ?? wants to plan a simple path, the path’s start point is node A,and the path’s destination is node B,?? will go from node A to node B. When ?? goes through a node(including node A and node B), he must first collects all keys, and then must open the boxes he can open in this node. The keys he got never disappear during the travel. Now ?? wants to know the maximum value he could get if he plan a best path.Can you help him? 

 

Input
The first line of the input gives the number of case T,T test cases follow.
Each case first line contains two integer n,m(n,m<=100000)indicating the number of nodes and the number of treasures.
Next n-1 lines each line contains two numbers ui and vi(1<=ui,vi<=n) indicates that there’s one road connecting node ui node vi.
Next m lines each line contains three number ui,vi,wi(1<=ui,vi<=n,-1000<=wi<=1000) indicates the position of ith-box’s key and the position of ith-box, and the value of treasure in the ith-box.

T<=30
The sum of n in all the test cases is no more than 600000
The sum of m in all the test cases is no more than 600000

 

Output
For each that case output”Case #x: y”,where x is the test case number(starting from 1),and y is the answer you get for that case.
 

Sample Input
  
  
2 4 2 1 2 2 3 3 4 1 1 100 2 4 -5 4 3 1 2 1 3 1 4 2 1 1 1 3 2 1 3 5
 

Sample Output
  
  
Case #1: 100 Case #2: 8

大意:一棵树有n个节点。现在有m个宝箱和m把钥匙。让你求一条简单路径,要求遇到钥匙必须拿,遇到宝箱能开则必须开。问你最多可以获得多少财富


我们考虑每一个宝箱在什么情况下会被统计

设钥匙在u,宝箱在v,价值为x

c=lca(u,v)

1、c!=u&&c!=v

从u的子树中的一个点到v的子树即可

2、c==u&&u!=v

令d为v到u上最靠近u的一个点

路径则为从不在d子树的任意点到v的子树

3、c==v&&u!=v

令d为v到u上最靠近u的一个点

路径则为从u的子树到不在d子树的任意点

4、u==v

这个处理起来略麻烦

我们考虑先给所有答案都加上x

然后考虑哪些路径不经过u,再减去x
那么就是u的所有子节点的子树内部点的组合和所有不在u子树内的点的组合


然后对于这些路径,我们可以用dfs序维护。那么路径就变成了一个个矩形

问题转化为求二维平面上被覆盖权值最大的点

扫描线+线段树维护最大值即可求解

#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct ak
{
	int u,v;
	int w;
}b[100001];
struct answer
{
	int l1,l2;
	int r1,r2;
	int x;
}ans1[400001],ans2[400001];
inline bool cmp1(answer x,answer y){return x.l1<y.l1;}
inline bool cmp2(answer x,answer y){return x.l2<y.l2;}
struct line
{
	 int s,t;
     int next;
}a[200001];
int head[100001];
int edge;
inline void add(int s,int t)
{
     a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
}
int tot;
int fa[100001];
int w[100001],ld[100001],rd[100001];
inline void dfs(int d)
{
	tot++;
	w[tot]=d;
	ld[d]=tot;
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(t!=fa[d])
		{
			fa[t]=d;
			dfs(t);
		}
	}
	rd[d]=tot;
}
bool v[100001];
int deep[100001];
int ans[100001][22];
inline void bfs(int r)
{
	 memset(deep,0,sizeof(deep));
	 memset(ans,0,sizeof(ans));
	 memset(v,false,sizeof(v));
     int i,j;
     deep[r]=1;
     for(i=0;i<=21;i++)
          ans[r][i]=r;
     queue <int>Q;
     while(!Q.empty())
          Q.pop();
     Q.push(r);
     v[r]=true;
     while(!Q.empty())
     {
          int d=Q.front();
          Q.pop();
          for(i=head[d];i!=0;i=a[i].next)
          {
               int t=a[i].t;
               if(!v[t])
               {
                    v[t]=true;
                    Q.push(t);
                    deep[t]=deep[d]+1;
                    ans[t][0]=d;
                    int dt;
					long long dc;
                    for(j=1;j<=21;j++)
                    {
                    	 dt=ans[t][j-1];
                         ans[t][j]=ans[dt][j-1];
                    }
               }
          }
     }
}
inline int swim(int x,int y)
{
     while(deep[x]!=deep[y])
     {
          int i=0;
          while(deep[ans[y][i]]>deep[x])
               i++;
          if(i!=0)
               i--;
          y=ans[y][i];
     }
     return y;
}
inline int lca(int x,int y)
{
     if(deep[x]>deep[y])
     {
          int t=x;
          x=y;
          y=t;
     }
     y=swim(x,y);
     while(x!=y)
     {
          int i=0;
          while(ans[x][i]!=ans[y][i])
               i++;
          if(i!=0)
               i--;
          x=ans[x][i];
          y=ans[y][i];
     }
     return x;
}
inline int find(int x,int y)
{
     while(deep[x]+1!=deep[y])
     {
          int i=0;
          while(deep[ans[y][i]]>deep[x])
               i++;
          if(i!=0)
               i--;
          y=ans[y][i];
     }
     return y;
}
struct tree
{
	int l,r;
	int x;
	int tag;
}tr[800001];
inline void push(int p)
{
	tr[p*2].x+=tr[p].tag;
	tr[p*2+1].x+=tr[p].tag;
	tr[p*2].tag+=tr[p].tag;
	tr[p*2+1].tag+=tr[p].tag;
	tr[p].tag=0;
}
inline void build(int p,int l,int r)
{
	tr[p].l=l;
	tr[p].r=r;
	if(l==r)
		return ;
	int mid=(l+r)/2;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}
inline void up(int p)
{
	tr[p].x=max(tr[p*2].x,tr[p*2+1].x);
}
inline void change(int p,int l,int r,int x)
{
	if(l<=tr[p].l&&tr[p].r<=r)
	{
		tr[p].x+=x;
		tr[p].tag+=x;
	}
	else
	{
		push(p);
		int mid=(tr[p].l+tr[p].r)/2;
		if(l<=mid)
			change(p*2,l,r,x);
		if(r>mid)
			change(p*2+1,l,r,x);
		up(p);
	}
}
inline int ask(int p,int l,int r)
{
	if(l<=tr[p].l&&tr[p].r<=r)
		return tr[p].x;
	else
	{
		push(p);
		int mid=(tr[p].l+tr[p].r)/2;
		int ansx=-2100000000;
		if(l<=mid)
			ansx=max(ansx,ask(p*2,l,r));
		if(r>mid)
			ansx=max(ansx,ask(p*2+1,l,r));
		return ansx;
	}
}
int value[100001];
int main()
{
	int k=0;
	int T;
	scanf("%d",&T);
	while(T>0)
	{
		k++;
		T--;
		memset(a,0,sizeof(a));
		memset(fa,0,sizeof(fa));
		memset(head,0,sizeof(head));
		memset(value,0,sizeof(value));
		edge=0;
		tot=0;
		int n,m;
		scanf("%d%d",&n,&m);
		int i,j;
		int ss,tt;
		for(i=1;i<=n-1;i++)
		{
			scanf("%d%d",&ss,&tt);
			edge++;
			add(ss,tt);
			edge++;
			add(tt,ss);
		}
		for(i=1;i<=m;i++)
			scanf("%d%d%d",&b[i].u,&b[i].v,&b[i].w);
		dfs(1);
		bfs(1);
		int p=0;
		int sum=0;
		for(i=1;i<=m;i++)
		{
			int c=lca(b[i].u,b[i].v);
			if(c!=b[i].u&&c!=b[i].v)
			{
				p++;
				ans1[p].l1=ld[b[i].u];
				ans1[p].l2=rd[b[i].u];
				ans1[p].r1=ld[b[i].v];
				ans1[p].r2=rd[b[i].v];
				ans1[p].x=b[i].w;
			}
			else if(b[i].u==b[i].v)
			{
				value[b[i].u]+=b[i].w;
				sum+=b[i].w;
			}
			else if(c==b[i].u)
			{
				int d=find(b[i].u,b[i].v);
				p++;
				ans1[p].l1=1;
				ans1[p].l2=ld[d]-1;
				ans1[p].r1=ld[b[i].v];
				ans1[p].r2=rd[b[i].v];
				ans1[p].x=b[i].w;
				p++;
				ans1[p].l1=rd[d]+1;
				ans1[p].l2=tot;
				ans1[p].r1=ld[b[i].v];
				ans1[p].r2=rd[b[i].v];
				ans1[p].x=b[i].w;
			}
			else if(c==b[i].v)
			{
				int d=find(b[i].v,b[i].u);
				p++;
				ans1[p].l1=ld[b[i].u];
				ans1[p].l2=rd[b[i].u];
				ans1[p].r1=1;
				ans1[p].r2=ld[d]-1;
				ans1[p].x=b[i].w;
				p++;
				ans1[p].l1=ld[b[i].u];
				ans1[p].l2=rd[b[i].u];
				ans1[p].r1=rd[d]+1;
				ans1[p].r2=tot;
				ans1[p].x=b[i].w;
			}
		}
		for(i=1;i<=n;i++)
		{
			if(value[i]!=0)
			{
				for(j=head[i];j!=0;j=a[j].next)
				{
					int t=a[j].t;
					if(t==fa[i])
						continue;
					p++;
					ans1[p].l1=ld[t];
					ans1[p].l2=rd[t];
					ans1[p].r1=ld[t];
					ans1[p].r2=rd[t];
					ans1[p].x=-value[i];
				}
				p++;
				ans1[p].l1=1;
				ans1[p].l2=tot;
				ans1[p].r1=1;
				ans1[p].r2=tot;
				ans1[p].x=value[i];
				p++;
				ans1[p].l1=1;
				ans1[p].l2=ld[i]-1;
				ans1[p].r1=1;
				ans1[p].r2=ld[i]-1;
				ans1[p].x=-value[i];
				p++;
				ans1[p].l1=rd[i]+1;
				ans1[p].l2=tot;
				ans1[p].r1=1;
				ans1[p].r2=ld[i]-1;
				ans1[p].x=-value[i];
				p++;
				ans1[p].l1=1;
				ans1[p].l2=ld[i]-1;
				ans1[p].r1=rd[i]+1;
				ans1[p].r2=tot;
				ans1[p].x=-value[i];
				p++;
				ans1[p].l1=rd[i]+1;
				ans1[p].l2=tot;
				ans1[p].r1=rd[i]+1;
				ans1[p].r2=tot;
				ans1[p].x=-value[i];
			}
		}
		for(i=1;i<=p;i++)
			ans2[i]=ans1[i];
		sort(ans1+1,ans1+1+p,cmp1);
		sort(ans2+1,ans2+1+p,cmp2);
		memset(tr,0,sizeof(tr));
		build(1,1,n);
		int d1=1,d2=1;
		int ansx=-2100000000;
		for(i=1;i<=n;i++)
		{
			while(ans1[d1].l1<=i&&d1<=p)
			{
				if(ans1[d1].l1<=ans1[d1].l2)
					change(1,ans1[d1].r1,ans1[d1].r2,ans1[d1].x);
				d1++;
			}
			ansx=max(ansx,ask(1,1,n));
			while(ans2[d2].l2<=i&&d2<=p)
			{
				if(ans2[d2].l1<=ans2[d2].l2)
					change(1,ans2[d2].r1,ans2[d2].r2,-ans2[d2].x);
				d2++;
			}
		}
		printf("Case #%d: %d\n",k,ansx);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值