1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 11816 Solved: 4787
[ 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
Source
题目链接:点我!!!
思路:树链抛分线段树本来是计算树上边的和,最大值等,只需要把线段树上记录的信息改为点就好了。
树链抛分推荐看神牛的博客,链接:http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html
代码时间到:
#include<iostream>
#include<cstdio>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
typedef unsigned long long LLu;
typedef long long LL;
const int maxn=2*1e5+100;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int MOD = 1e9+7;
struct node{
int sum,ma;
};
node A[maxn];
int B[maxn];//结点价值
int W[maxn];//结点对应线段树中位置
int head[maxn];
int Next[maxn];
int info[maxn];
int siz[maxn];
int son[maxn];
int top[maxn];
int dep[maxn];
int fa[maxn];
int tot,tow;
int n;
void init(){
for(int i=0;i<maxn;i++){
A[i].sum=A[i].ma=-INF;
top[i]=i;
}
memset(head,-1,sizeof head);
memset(dep,0,sizeof dep);
memset(fa,-1,sizeof fa);
tot=tow=0;
}
void add(int fr,int to){
Next[tot]=head[fr];
info[tot]=to;
head[fr]=tot++;
}
void update(int a,int val,int l,int r,int rt){
if(l==r){
A[rt].ma=val;
A[rt].sum=val;
return ;
}
int mid=(l+r)>>1;
if(a<=mid) update(a,val,lson);
else update(a,val,rson);
A[rt].sum=A[rt<<1].sum+A[rt<<1|1].sum;
A[rt].ma=max(A[rt<<1].ma,A[rt<<1|1].ma);
}
int query(char c,int L,int R,int l,int r,int rt){
if(L<=l&&R>=r){
if(c=='m'){
return A[rt].ma;
}
else return A[rt].sum;
}
if(c=='m'){
int mid=(l+r)>>1;
int ans=-INF;
if(L<=mid) ans=max(ans,query(c,L,R,lson));
if(R>mid) ans=max(ans,query(c,L,R,rson));
return ans;
}
else{
int mid=(l+r)>>1;
int ans=0;
if(L<=mid) ans+=query(c,L,R,lson);
if(R>mid) ans+=query(c,L,R,rson);
return ans;
}
}
void dfs1(int a,int f){
siz[a]=1;
int k=-1;
for(int i=head[a];i!=-1;i=Next[i]){
if(info[i]==f) continue;
dep[info[i]]=dep[a]+1;
fa[info[i]]=a;
dfs1(info[i],a);
if(k==-1||siz[info[i]]>siz[k]) k=info[i];
siz[a]+=siz[info[i]];
}
if(k!=-1) son[a]=k;
else son[a]=-1;
}
void dfs2(int a,int f){
W[a]=++tow;
update(tow,B[a],1,n,1);
if(son[a]!=-1){
top[son[a]]=top[a];
dfs2(son[a],a);
}
for(int i=head[a];i!=-1;i=Next[i]){
if(info[i]==f||son[a]==info[i]) continue;
dfs2(info[i],a);
}
}
int find1(char c,int L,int R){
if(c=='m'){
int f1=top[L],f2=top[R],ans=-INF;
while(f1!=f2){
// printf("%d %d\n",f1,f2);
if(dep[f1]>dep[f2]){
swap(f1,f2);
swap(L,R);
}
ans=max(ans,query('m',W[f2],W[R],1,n,1));
R=fa[f2];
f2=top[R];
}
if(L==R) return max(ans,B[L]);
if(dep[L]>dep[R]) swap(L,R);
return max(ans,query('m',W[L],W[R],1,n,1));
}
else{
int f1=top[L],f2=top[R];
int ans=0;
while(f1!=f2){
if(dep[f1]>dep[f2]){
swap(f1,f2);
swap(L,R);
}
ans+=query('s',W[f2],W[R],1,n,1);
R=fa[f2];
f2=top[R];
}
if(L==R) return ans+=B[L];
if(dep[L]>dep[R]) swap(L,R);
ans+=query('s',W[L],W[R],1,n,1);
return ans;
}
}
int main(){
init();
int i,j,k;
scanf("%d",&n);
for(i=1;i<n;i++){
scanf("%d%d",&j,&k);
add(j,k);
add(k,j);
}
for(i=1;i<=n;i++){
scanf("%d",&B[i]);
}
dfs1(1,-1);
// cout<<n<<endl;
dfs2(1,-1);
int m;
scanf("%d",&m);
while(m--){
char s[10];
int a,b;
scanf("%s%d%d",s,&a,&b);
if(s[0]=='C'){
B[a]=b;
update(W[a],b,1,n,1);
}
else if(s[1]=='M'){
printf("%d\n",find1('m',a,b));
}
else if(s[1]=='S'){
printf("%d\n",find1('s',a,b));
}
}
return 0;
}