一棵树上有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个节点,编号分别为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”的操作,每行输出一个整数表示要求输出的结果。
树的分治
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int maxn=43000; const int INF=0x3f3f3f3f; struct Edge { int to,next; }edge[2*maxn]; int Adj[maxn],Size; void init_edge() { memset(Adj,-1,sizeof(Adj)); Size=0; } void add_edge(int u,int v) { edge[Size].to=v; edge[Size].next=Adj[u]; Adj[u]=Size++; } int fa[maxn],deep[maxn],num[maxn],son[maxn]; int top[maxn],p[maxn],rp[maxn],pos; void init() { init_edge(); memset(son,-1,sizeof(son)); pos=1; } void dfs1(int u,int pre,int d) { num[u]=1; fa[u]=pre; deep[u]=d; for(int i=Adj[u];~i;i=edge[i].next) { int v=edge[i].to; if(v==pre) continue; dfs1(v,u,d+1); num[u]+=num[v]; if(son[u]==-1||num[son[u]]<num[v]) { son[u]=v; } } } void getPos(int u,int to) { top[u]=to; p[u]=pos++; rp[p[u]]=u; if(son[u]!=-1) getPos(son[u],to); for(int i=Adj[u];~i;i=edge[i].next) { int v=edge[i].to; if(v!=fa[u]&&v!=son[u]) getPos(v,v); } } #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int SUM[maxn<<2]; int MAX[maxn<<2]; int w[maxn]; void push_up(int rt) { MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); SUM[rt]=SUM[rt<<1]+SUM[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r) { SUM[rt]=MAX[rt]=w[rp[l]]; return ; } int m=(l+r)/2; build(lson); build(rson); push_up(rt); } void update(int C,int V,int l,int r,int rt) { if(l==r) { MAX[rt]=V; SUM[rt]=V; return ; } int m=(l+r)/2; if(C<=m) update(C,V,lson); else update(C,V,rson); push_up(rt); } int query_sum(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return SUM[rt]; } int m=(l+r)/2; int ret=0; if(L<=m) ret+=query_sum(L,R,lson); if(R>m) ret+=query_sum(L,R,rson); return ret; } int query_max(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return MAX[rt]; } int m=(l+r)/2; int mx=-(1<<28); if(L<=m) mx=max(mx,query_max(L,R,lson)); if(R>m) mx=max(mx,query_max(L,R,rson)); return mx; } int n,m; int Q_max(int u,int v) { if(u==v) return query_max(p[u],p[u],1,n,1); int f1=top[u],f2=top[v]; int ret=-INF; while(f1!=f2) { if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } ret=max(ret,query_max(p[f1],p[u],1,n,1)); u=fa[f1];f1=top[u]; } //if(u==v) return ret; if(deep[u]>deep[v]) swap(u,v); ret=max(ret,query_max(p[u],p[v],1,n,1)); return ret; } int Q_sum(int u,int v) { if(u==v) return query_sum(p[u],p[u],1,n,1); int f1=top[u],f2=top[v]; int ret=0; while(f1!=f2) { if(deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } ret+=query_sum(p[f1],p[u],1,n,1); u=fa[f1]; f1=top[u]; } //if(u==v) return ret; if(deep[u]>deep[v]) swap(u,v); ret+=query_sum(p[u],p[v],1,n,1); return ret; } int main() { while(scanf("%d",&n)!=EOF) { init(); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } dfs1(1,-1,0); getPos(1,1); //cout<<"son1: "<<son[1]<<" fa: "<<fa[1]<<endl; for(int i=1;i<=n;i++) { scanf("%d",&w[i]); } build(1,n,1); scanf("%d",&m); char op[20]; while(m--) { int a,b; scanf("%s%d%d",op,&a,&b); if(op[1]=='M') { printf("%d\n",Q_max(a,b)); } else if(op[1]=='S') { printf("%d\n",Q_sum(a,b)); } else if(op[1]=='H') { update(p[a],b,1,n,1); } } } return 0; }