1. 程式人生 > >HDU-5692-Snacks(DFS序+線段樹,單點修改,區間查詢)

HDU-5692-Snacks(DFS序+線段樹,單點修改,區間查詢)

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5692

Problem Description

百度科技園內有n 個零食機,零食機之間通過n−1 條路相互連通。每個零食機都有一個值v ,表示為小度熊提供零食的價值。

由於零食被頻繁的消耗和補充,零食機的價值v 會時常發生變化。小度熊只能從編號為0的零食機出發,並且每個零食機至多經過一次。另外,小度熊會對某個零食機的零食有所偏愛,要求路線上必須有那個零食機。

為小度熊規劃一個路線,使得路線上的價值總和最大。

 

 

Input

輸入資料第一行是一個整數T(T≤10) ,表示有T 組測試資料。

對於每組資料,包含兩個整數n,m(1≤n,m≤100000) ,表示有n 個零食機,m 次操作。

接下來n−1 行,每行兩個整數x 和y(0≤x,y<n) ,表示編號為x 的零食機與編號為y 的零食機相連。

接下來一行由n 個數組成,表示從編號為0到編號為n−1 的零食機的初始價值v(|v|<100000) 。

接下來m 行,有兩種操作:0 x y ,表示編號為x 的零食機的價值變為y ;1 x ,表示詢問從編號為0的零食機出發,必須經過編號為x 零食機的路線中,價值總和的最大值。

本題可能棧溢位,辛苦同學們提交語言選擇c++,並在程式碼的第一行加上:

`#pragma comment(linker, "/STACK:1024000000,1024000000") `

 

 

Output

對於每組資料,首先輸出一行”Case #?:”,在問號處應填入當前資料的組數,組數從1開始計算。

對於每次詢問,輸出從編號為0的零食機出發,必須經過編號為x 零食機的路線中,價值總和的最大值。

 

Sample Input
1
6 5
0 1
1 2
0 3
3 4
5 3
7 -5 100 20 -5 -7
1 1
1 3
0 2 -1
1 1
1 5
 

Sample Output
Case #1:
102
27
2
20
 

中文題,題意很好懂,題目可以理解成:對於一棵樹,修改一個點,或,查詢那顆點一下的子樹的的最大值,很容易想到線段樹解決,學了一下DFS序,發現這道題是 問題1的變形,只不過換成取最大值,理解DFS序後就比較簡單了;

注意,我這裡沒法用memset,因為用之後就直接70K+的記憶體空間,直接MLE,但改成手動賦值之後就只有13K+的記憶體空間,我也不太清楚,還有就是輸入輸出scanf,負責會TLE。。

ac:

#pragma comment(linker, "/STACK:1024000000,1024000000") 
 
#include<stdio.h>
#include<string.h>  
#include<math.h>  
#include<stdlib.h>

//#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<fstream>
#include<iostream>  
#include<algorithm>  
using namespace std;  
 
#define ll long long  
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b) 
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
//std::ios::sync_with_stdio(false);
const int MAXN=1e5+5;
const ll INF=1e18;
const ll mod=1e9+7; 
struct node{
	int v,w,nxt;
	node(int _v=0,int _nxt=0):
	v(_v),nxt(_nxt){}
}edge[MAXN<<1];
int head[MAXN],ecnt;
ll tree[MAXN<<2],add[MAXN<<2],value[MAXN],dis[MAXN];
int L[MAXN],R[MAXN],arr[MAXN];
//x所對應線上段樹左的節點,同理右,線段樹上x對應的節點是多少arr[x]; 
int n,m,cnt;

void intt()
{
//	clean(L,0);
//	clean(R,0);
//	clean(dis,0);
//	clean(add,0);
//	clean(tree,0);
//	clean(value,0);
	clean(head,-1);	
//	memset(head,-1,sizeof(head));
	ecnt=0;
	cnt=0;//從0開始變成從1開始 
} 
void add_edge(int u,int v)
{	
	edge[ecnt]=node(v,head[u]);	
	head[u]=ecnt++;
}

void dfs(int u,int fa)
{
	L[u]=++cnt;
	arr[cnt]=u;
	for(int i=head[u];i+1;i=edge[i].nxt)
	{
		int v=edge[i].v;
		if(v==fa)
			continue;
		dis[v]=dis[u]+value[v];
		dfs(v,u);
	}
	R[u]=cnt;
}

void push_down(int rt)
{
	if(add[rt])
	{
		tree[rt<<1]+=add[rt];
		tree[rt<<1|1]+=add[rt];
		
		add[rt<<1]+=add[rt];
		add[rt<<1|1]+=add[rt];
		add[rt]=0;
	}
}

void build_tree(int l,int r,int rt)
{
	add[rt]=0;
	if(l==r)
	{
		tree[rt]=dis[arr[l]];
		return ;
	}
	int mid=(l+r)>>1;
	build_tree(l,mid,rt<<1);
	build_tree(mid+1,r,rt<<1|1);
	tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}

void updata(int left,int right,int val,int l,int r,int rt)
{
	if(left<=l&&right>=r)//找到目標範圍 
	{
		add[rt]+=val;
		tree[rt]+=val;
		return ;
	}
	//有一部分在範圍外 
	push_down(rt);//向下推進 
	int mid=(l+r)>>1;
	if(left<=mid)
		updata(left,right,val,l,mid,rt<<1);
	if(right>mid)
		updata(left,right,val,mid+1,r,rt<<1|1);
	tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}

ll Query(int left,int right,int l,int r,int rt)
{
	if(left<=l&&right>=r)
		return tree[rt];
	push_down(rt);
	int mid=(l+r)>>1;
	ll ans=-INF;
	if(left<=mid)
		ans=max(ans,Query(left,right,l,mid,rt<<1));
	if(right>mid)
		ans=max(ans,Query(left,right,mid+1,r,rt<<1|1));
	return ans;
}

int main()
{
	//std::ios::sync_with_stdio(false);
    int T,Case=1;
    scanf("%d",&T);
    while(T--)
    {
    	//cout<<"T: "<<T<<endl;
    	intt();
    	scanf("%d%d",&n,&m);
    	int a,b;
    	for(int i=1;i<n;++i)//建邊 
    	{
    		scanf("%d%d",&a,&b);
    		add_edge(a,b);
    		add_edge(b,a);
		}
		for(int i=0;i<n;++i)//讀入權值 
			scanf("%lld",&value[i]);//cin>>value[i];
		dis[0]=value[0];
		dfs(0,-1);
		build_tree(1,n,1);
		bool oper;
		cout<<"Case #"<<Case++<<":"<<endl;
		for(int i=1;i<=m;++i)
		{
			scanf("%d",&oper);
			if(oper)//找 
			{
				scanf("%d",&a);
				cout<<Query(L[a],R[a],1,n,1)<<endl;
			}
			else//換 
			{
				scanf("%d%d",&a,&b);
				updata(L[a],R[a],b-value[a],1,n,1);
				value[a]=b;
			}
		}
	}
}

/*
Sample Input
1
6 5
0 1
1 2
0 3
3 4
5 3
7 -5 100 20 -5 -7
1 1
1 3
0 2 -1
1 1
1 5
 

Sample Output
Case #1:
102
27
2
20
*/