1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 17520 Solved: 7150
[ Submit][ Status][ Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
1
2
2
10
6
5
6
5
16
HINT
做的第一道树链刨分题,这也是一道树链刨分经典题,呢什么是树链刨分呢
参考博客:树链刨分详解
树链,即树上的路径,现在我们的任务是所谓的剖分。所以我们可以看出,树链剖分并不是一种单独的数据结构,
不像堆,线段树等等,而是直接在一棵普通的树上处理,然而单是这一课树是并没有什么卵用的。今天先讲一个
相对比较简单的情况——用一棵线段树维护主树每条边的权值。
void dfs1(int u,int p)
{
int i;
fa[u]=p;
dep[u]=dep[p]+1;
for(i=0;i<q[u].size();i++)
{
int v=q[u][i];
if(v==p)
continue;
dfs1(v,u);
siz[u]+=siz[v]+1;
if(son[u]==0 || siz[v]>siz[son[u]])
son[u]=v;
}
}
void dfs2(int u,int p)
{
int i;
top[u]=p;
rak[u]=++cnt;
id[cnt]=u;
if(son[u]==0)
return;
dfs2(son[u],p);
for(i=0;i<q[u].size();i++)
{
int v=q[u][i];
if(v==son[u] || v==fa[u])
continue;
dfs2(v,v);
}
}
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<math.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 1000000000
#define mod 1000000007
#define maxn 200005
#define lowbit(x) (x&-x)
#define eps 1e-10
vector<int>q[maxn];
int dep[maxn],son[maxn],top[maxn],n,id[maxn];
int rak[maxn],fa[maxn],a[maxn],cnt,siz[maxn];
struct node
{
int maxs,sum;
}tr[maxn];
void dfs1(int u,int p)
{
int i;
fa[u]=p;
dep[u]=dep[p]+1;
for(i=0;i<q[u].size();i++)
{
int v=q[u][i];
if(v==p)
continue;
dfs1(v,u);
siz[u]+=siz[v]+1;
if(son[u]==0 || siz[v]>siz[son[u]])
son[u]=v;
}
}
void dfs2(int u,int p)
{
int i;
top[u]=p;
rak[u]=++cnt;
id[cnt]=u;
if(son[u]==0)
return;
dfs2(son[u],p);
for(i=0;i<q[u].size();i++)
{
int v=q[u][i];
if(v==son[u] || v==fa[u])
continue;
dfs2(v,v);
}
}
void build(int x,int l,int r)
{
if(l==r)
{
tr[x].maxs=a[id[l]];
tr[x].sum=a[id[l]];
return;
}
int m=(l+r)/2;
build(x*2,l,m);
build(x*2+1,m+1,r);
tr[x].sum=tr[x*2].sum+tr[x*2+1].sum;
tr[x].maxs=max(tr[x*2].maxs,tr[x*2+1].maxs);
}
void updata(int id,int l,int r,int x,int y)
{
if(l==r && l==x)
{
tr[id].maxs=y;
tr[id].sum=y;
return;
}
int m=(l+r)/2;
if(x<=m)
updata(id*2,l,m,x,y);
else
updata(id*2+1,m+1,r,x,y);
tr[id].sum=tr[id*2].sum+tr[id*2+1].sum;
tr[id].maxs=max(tr[id*2].maxs,tr[id*2+1].maxs);
}
int querym(int x,int l,int r,int L,int R)
{
if(l>=L && r<=R)
return tr[x].maxs;
int m=(l+r)/2,res=-inf;
if(L<=m)
res=max(res,querym(x*2,l,m,L,R));
if(R>m)
res=max(res,querym(x*2+1,m+1,r,L,R));
return res;
}
int trquerym(int x,int y)
{
int t1,t2,now=-inf;
t1=top[x];t2=top[y];
while(t1!=t2)
{
if(dep[t1]<dep[t2])
swap(t1,t2),swap(x,y);
now=max(now,querym(1,1,n,rak[t1],rak[x]));
x=fa[t1];t1=top[x];
}
if(dep[x]>dep[y])
swap(x,y);
now=max(now,querym(1,1,n,rak[x],rak[y]));
return now;
}
int querys(int x,int l,int r,int L,int R)
{
if(l>=L && r<=R)
return tr[x].sum;
int m=(l+r)/2,res=0;
if(L<=m)
res+=querys(x*2,l,m,L,R);
if(R>m)
res+=querys(x*2+1,m+1,r,L,R);
return res;
}
int trquerys(int x,int y)
{
int t1,t2,sum=0;
t1=top[x];t2=top[y];
while(t1!=t2)
{
if(dep[t1]<dep[t2])
swap(t1,t2),swap(x,y);
sum+=querys(1,1,n,rak[t1],rak[x]);
x=fa[t1];t1=top[x];
}
if(dep[x]>dep[y])
swap(x,y);
sum+=querys(1,1,n,rak[x],rak[y]);
return sum;
}
int main(void)
{
char s[20];
int i,j,x,y,m;
scanf("%d",&n);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
q[x].push_back(y);
q[y].push_back(x);
}
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs1(1,0);dfs2(1,1);
build(1,1,n);
scanf("%d",&m);
while(m--)
{
scanf("%s%d%d",s,&x,&y);
if(s[0]=='C')
updata(1,1,n,rak[x],y);
else if(s[1]=='M')
printf("%d\n",trquerym(x,y));
else
printf("%d\n",trquerys(x,y));
}
return 0;
}