题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5692
Problem Description 百度科技园内有n 个零食机,零食机之间通过n−1 条路相互连通。每个零食机都有一个值v ,表示为小度熊提供零食的价值。 Input 输入数据第一行是一个整数T(T≤10) ,表示有T 组测试数据。 Output 对于每组数据,首先输出一行”Case #?:”,在问号处应填入当前数据的组数,组数从1开始计算。 Sample Input Sample Output |
中文题,题意很好懂,题目可以理解成:对于一棵树,修改一个点,或,查询那颗点一下的子树的的最大值,很容易想到线段树解决,学了一下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
*/