一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
输入的第一行为一个整数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之间。
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
4
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
4
1
2
2
10
6
5
6
5
16
感谢wfwbz的指导
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<vector>
#define R0(i,n) for(register int i=0;i<n;++i)
#define R1(i,n) for(register int i=1;i<=n;++i)
#define cl(x,c) memset(x,c,sizeof x)
#define INF 0x3f3f3f3f
#define mn 30010
using namespace std;
typedef long long ll;
template <class T> inline void read(T&x){
bool f = false; char ch;
for (ch = getchar(); ch <= 32; ch = getchar());
if (ch == ‘-‘) f = true, ch = getchar();
for (x = 0; ch > 32; ch = getchar()) x = x * 10 + ch - ‘0‘;
if (f) x = -x;
}
template <class T> inline void write(T x){
if (x < 0) putchar(‘-‘), x = -x;
if (x < 10)
putchar(x + ‘0‘);
else
write(x / 10), putchar(x % 10 + ‘0‘);
}
template <class T> inline void writeln(T x){
write(x);puts("");
}
void setIO(string t){
string a=t+".in",b=t+".out";
freopen(a.c_str(),"r",stdin);
freopen(b.c_str(),"w",stdout);
}
//数据
int _[mn],__[mn],n,m;
//线段树
#define lc k<<1
#define rc k<<1|1
#define M ((l+r)>>1)
#define All 1,1,n
#define lson lc,l,M
#define rson rc,M+1,r
int sumv[mn<<2], maxv[mn<<2];
void push_up(int k){
sumv[k] = sumv[lc] + sumv[rc];
maxv[k] = max(maxv[lc], maxv[rc]);
}
void build(int k,int l,int r){
if(l==r)sumv[k]=maxv[k]=__[l];
else build(lson),build(rson),push_up(k);
}
int _l, _r,_a,_b;//全局变量减少传的参数
int query_sum(int k,int l,int r){
if(_l<=l&&r<=_r)return sumv[k];
int ret = 0;
if(_l<=M)ret+=query_sum(lson);
if(M<_r) ret+=query_sum(rson);
return ret;
}
int query_max(int k,int l,int r){
if(_l<=l&&r<=_r)return maxv[k];
int ret=-INF;
if(_l<=M) ret=max(ret,query_max(lson));
if(M <_r) ret=max(ret,query_max(rson));
return ret;
}
void update(int k,int l,int r) {
if(l==_a &&r==_a)sumv[k]=maxv[k]=_b;
else {
if(_a<=M) update(lson);
else update(rson);
push_up(k);
}
}
//重链剖分
int dep[mn],fa[mn],size[mn],tid[mn],top[mn],son[mn];
/*
dep深度
fa父亲节点
size以i为根的子树节点个数
tid新编号
top祖先
son孩子节点
这一块还不太明白如果有错欢迎指正
*/
vector<int>ch[mn];
void f_h_e(int x,int father,int depth){//找重边
dep[x]=depth,fa[x]=father,size[x]=1;
int maxsize=0;
R0(i,ch[x].size()){
int child=ch[x][i];
if(child!=father){
f_h_e(child,x,depth+1);
size[x]+=size[child];
if(size[child]>maxsize)maxsize=size[child],son[x]=child;
}
}
}
int label;//新编号用
void c_h_e(int x,int anc){//连重链
__[tid[x]=++label]=_[x];//按新编号排列数据
top[x]=anc;//top 重链祖先
if(son[x]){
c_h_e(son[x],anc);
R0(i,ch[x].size()){
int child=ch[x][i];
if(child!=fa[x]&&child!=son[x])c_h_e(child,child);//轻的自己连自己
}
}
}
//修改
//单点修改直接走数据结构
//询问
int ask_sum(int x,int y){
int ret=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
_l=tid[top[x]],_r=tid[x],ret+=query_sum(All);
x=fa[top[x]];
}//不在同一条重链上
if(dep[x]>dep[y])swap(x,y);
_l=tid[x],_r=tid[y],ret+=query_sum(All);
return ret;//到达同一条重链
}
int ask_max(int x,int y){
int ret=-INF;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
_l=tid[top[x]],_r=tid[x],ret=max(ret,query_max(All));
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
_l=tid[x],_r=tid[y],ret=max(ret,query_max(All));
return ret;
} //同上
int main(){
read(n);int a,b;
R1(i,n-1){
read(a),read(b);
ch[a].push_back(b);
ch[b].push_back(a);
}
R1(i,n)read(_[i]);
//
cl(maxv,-0x3f);
f_h_e(1,1,1);
c_h_e(1,1);
build(All);
read(m);
char cmd[7];
R0(i,m){
scanf("%s",cmd);
read(a),read(b);
switch(cmd[1]){
case‘S‘:{writeln(ask_sum(a,b));break;}
case‘M‘:{writeln(ask_max(a,b));break;}
case‘H‘:{_a=tid[a],_b=b;update(All);break;}//这里_a要用新标号
}
}
return 0;
}
原文:http://blog.csdn.net/iostream0/article/details/43983119