【链接】
HDU5962
【题目大意】
给定你一颗n个节点树,有m个操作,操作有两种:0 x y表示将x节点的点权修改成y,1 x表示询问从节点0开始中途经过节点x的路线中点权加和最大的值。
【解题报告】
从题目中可以确定根节点是0。对于每次修改,其实需要修改的只有经过以给定的x为根的子树的节点的路线的值,直接修改复杂度太大,那该如何修改呢?我们可以通过DFS序,将树转化为区间,这样修改就转化为区间修改了,直接用线段树维护0到每个节点路线的值就好了。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=100005,maxm=200005,maxv=400005;
int T,n,m,tot,Time,id[maxn],in[maxn],out[maxn],lnk[maxn],son[maxm],nxt[maxm],w[maxn];
LL dep[maxn];
struct Node
{
int l[maxv],r[maxv];
LL MAX[maxv],Save[maxv];
void Pushup(int d){MAX[d]=max(MAX[d<<1],MAX[(d<<1)+1]);}
void Pushdown(int d)
{
LL p=Save[d];
Save[d<<1]+=p; Save[(d<<1)+1]+=p;
MAX[d<<1]+=p; MAX[(d<<1)+1]+=p; Save[d]=0;
}
void Build(int L,int R,int d)
{
l[d]=L; r[d]=R;
if (L==R) {MAX[d]=dep[id[L]]; return;}
int mid=(R-L>>1)+L;
Build(L,mid,d<<1); Build(mid+1,R,(d<<1)+1);
Pushup(d);
}
void Insert(int x,int y,int d,int p)
{
int L=l[d],R=r[d];
if (x==L&&y==R) {Save[d]+=p; MAX[d]+=p;return;}
Pushdown(d);
int mid=(R-L>>1)+L;
if (y<=mid) Insert(x,y,d<<1,p);
else if (x>mid) Insert(x,y,(d<<1)+1,p);
else Insert(x,mid,d<<1,p),Insert(mid+1,y,(d<<1)+1,p);
Pushup(d);
}
LL Query(int x,int y,int d)
{
int L=l[d],R=r[d];
if (x==L&&y==R) return MAX[d];
Pushdown(d);
int mid=(R-L>>1)+L;
if (y<=mid) Query(x,y,d<<1);
else if (x>mid) Query(x,y,(d<<1)+1);
else return max(Query(x,mid,d<<1),Query(mid+1,y,(d<<1)+1));
}
}tr;//线段树
inline int Read()
{
int res=0,f=1;
char ch=getchar(),cc=ch;
while (ch<'0'||ch>'9') cc=ch,ch=getchar();
if (cc=='-') f=-1;
while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=getchar();
return res*f;
}
void Add(int x,int y)
{
son[++tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;
}
void Dfs(int x,int fa)//DFS序
{
in[x]=++Time; id[Time]=x; dep[x]=dep[fa]+w[x];
for (int j=lnk[x]; j>=0; j=nxt[j])
if (son[j]!=fa) Dfs(son[j],x);
out[x]=Time;
}
void Work(int d)
{
printf("Case #%d:\n",d);
n=Read(); m=Read(); tot=Time=0;
memset(lnk,255,sizeof(lnk));
memset(dep,0,sizeof(dep));
memset(tr.Save,0,sizeof(tr.Save));
for (int i=1,x,y; i<n; i++) x=Read(),y=Read(),Add(x,y),Add(y,x);
for (int i=0; i<n; i++) w[i]=Read();
Dfs(0,n); tr.Build(1,n,1);
for (int i=1; i<=m; i++)
{
int z=Read(),x=Read(),p;
if (z==1) printf("%lld\n",tr.Query(in[x],out[x],1));
else p=Read(),tr.Insert(in[x],out[x],1,p-w[x]),w[x]=p;
}
}
int main()
{
freopen("5692.in","r",stdin);
freopen("5692.out","w",stdout);
T=Read();
for (int i=1; i<=T; i++) Work(i);
return 0;
}