题目链接:点击打开链接
题目大意:有一棵树,30000个点,每个点有权值,接下来有20w个操作,分为三种,一是改变某个点的权值,二是询问从a到b的路径上的点的权值的最大值,三是询问a到b上点的权值和。
一道裸的树链剖分+线段树:
对于树上的路径问题,可以先进行轻重链划分,再用线段树解决。
轻重链剖分和点的重标号可以用dfs也可以用bfs
#include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
#include <cstdio>
#define ll long long
#define N 30005
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef struct{
int l,r,rt;
ll maxn,sum;
}node;
typedef struct{
int v;
}next;
vector<next>edge[N<<1];
node Tree[N<<4];
int weight[N];
int sz[N],son[N],maxn[N],q[N],Index[N],dep[N],fa[N],top[N],w[N],id[N];//id用来记录当前的点属于哪个链
void PushUp(int rt){
Tree[rt].maxn = max(Tree[ls].maxn,Tree[rs].maxn);
Tree[rt].sum = Tree[ls].sum + Tree[rs].sum;
}
void update(int p,int x,int rt){
if(p == Tree[rt].l && p ==Tree[rt].r){
Tree[rt].sum = x;
Tree[rt].maxn = x;
return ;
}
int mid;
mid = (Tree[rt].l + Tree[rt].r) >> 1;
if(p <= mid) update(p,x,ls);
else update(p,x,rs);
PushUp(rt);
}
void Build(int l,int r,int rt){
Tree[rt].l = l;
Tree[rt].r = r;
if(l == r){
Tree[rt].maxn = weight[Index[l]];
Tree[rt].sum = weight[Index[l]];
return ;
}
int mid;
mid = (l + r) >> 1 ;
Build(l,mid,ls);
Build(mid+1,r,rs);
PushUp(rt);
}
ll query(int op,int l,int r,int rt){
if(Tree[rt].l == l&&Tree[rt].r == r){
if(op == 0) return Tree[rt].maxn;
else if(op == 1) return Tree[rt].sum;
}
int mid;
mid =(Tree[rt].l+Tree[rt].r) >> 1;
if(r <= mid) return query(op,l,r,ls);
else if(l>mid) return query(op,l,r,rs);
else {
if(op == 0) return max(query(op,l,mid,ls),query(op,mid+1,r,rs));
else if(op == 1) return query(op,l,mid,ls)+query(op,mid+1,r,rs);
}
}
int lca(int x,int y){//重链的id一定小于轻边的id
while(id[x]!=id[y]){
if(id[x] > id[y]) swap(x,y);
y = fa[top[y]];
}
if(dep[x] > dep[y]) swap(x,y);
return x;
}
ll op1(int Lca,int a,int b){//对路径上的每一段连续的线段进行查询
ll ret = -6000000000;
while(1){
if(dep[top[a]] <=dep[Lca]){
ret = max(ret,query(0,w[Lca],w[a],1));
break;
}
else {
ret = max(ret,query(0,w[top[a]],w[a],1));
a = fa[top[a]];
}
}
while(1){
if(dep[top[b]] <= dep[Lca]){
ret = max(ret,query(0,w[Lca],w[b],1));
break;
}
else {
ret = max(ret,query(0,w[top[b]],w[b],1));
b = fa[top[b]];
}
}
return ret;
}
ll op2(int Lca,int a,int b){
ll ret = 0;
while(1){
if(dep[top[a]] <=dep[Lca]){
ret +=query(1,w[Lca],w[a],1);
break;
}
else {
ret += query(1,w[top[a]],w[a],1);
a = fa[top[a]];
}
}
while(1){
if(dep[top[b]] <=dep[Lca]){
ret += query(1,w[Lca],w[b],1);
break;
}
else {
ret += query(1,w[top[b]],w[b],1);
b = fa[top[b]];
}
}
ret -= query(1,w[Lca],w[Lca],1);
return ret;
}
void init(){
memset(maxn,-1,sizeof(maxn));
memset(sz,0,sizeof(sz));
memset(son,0,sizeof(son));
}
void bfs(int x){
int f,r,u,v,time,cnt;
f = r = 0;
q[r++] = x;
dep[x] = 1;
while(f<r){
u = q[f++];
for(int i = 0;i<edge[u].size();i++){
v = edge[u][i].v;
if(v!=fa[u]){
fa[v] = u;
dep[v] = dep[u] + 1;
q[r++] = v;
}
}
}
for(int i = r-1;i>=0; i--){
sz[fa[q[i]]] += ++sz[q[i]];
if(maxn[fa[q[i]]] < sz[q[i]]){
maxn[fa[q[i]]] = sz[q[i]];
son[fa[q[i]]] = q[i];
}
}
fa[1] = 1;
for(int i = 0;i < r; i++){
if(son[fa[q[i]]]!=q[i]){
top[q[i]] = q[i];
}
else{
top[q[i]] = top[fa[q[i]]];
}
}
cnt = 0;
f = 0;r = 1;
q[0] = x;
while(f<r){
u = q[f++];
if(top[u] == u) id[u] = ++cnt;
else{
id[u] = id[top[u]];
}
for(int i = 0;i<edge[u].size();i++){
v = edge[u][i].v;
if(v!=fa[u]) q[r++] = v;
}
}
f = 0;r = cnt = 1;
q[0] = x;
while(f<r){
u = q[f++];
v = u;
Index[cnt] = v;
w[v] = cnt++;
while(son[v]){
for(int i = 0;i<edge[v].size();i++){
if(edge[v][i].v!=fa[v]&&edge[v][i].v!=son[v]){
q[r++] = edge[v][i].v;
}
}
v = son[v];
Index[cnt] = v;
w[v] = cnt++;
}
}
}
/*int dfs(int x,int f,int de){//dfs法
int s = 1,v,maxx = 0,tmp;
fa[x] = f;
dep[x] = de;
for(int i=0;i<edge[x].size();i++){
v = edge[x][i].v;
if(v!=f){
tmp = dfs(v,x,de+1);
if(tmp > maxx){
son[x] = v;
maxx = tmp;
}
s += tmp;
}
}
return sz[x] = s;
}
int Time = 1,cnt = 0;
void dfs2(int x,int tp){
int v;
top[x] = tp;
Index[Time] = x;
w[x] = Time++;
if(son[x]) dfs2(son[x],tp);
for(int i = 0;i < edge[x].size();i++){
v = edge[x][i].v;
if(v!=fa[x]){
if(v != son[x]) dfs2(v,v);
}
}
}
void deal(int x){
int f,r,u,v;
f = 0;r = 1;
q[0] = x;
while(f<r){
u = q[f++];
if(top[u] == u)
id[u] = ++cnt;
else{
id[u] = id[top[u]];
}
for(int i = 0;i<edge[u].size();i++){
v = edge[u][i].v;
if(v!=fa[u]) q[r++] = v;
}
}
}*/
char opr[34];
int main(){
init();
int n,a,b,q;
ll ans;
next tmp;
cin>>n;
for(int i = 0;i < n-1;i++){
scanf("%d%d",&a,&b);
tmp.v = b;
edge[a].push_back(tmp);
tmp.v = a;
edge[b].push_back(tmp);
}
for(int i = 1;i <= n; i++){
scanf("%d",&weight[i]);
}
bfs(1);
//dfs(1,1,1);
//dfs2(1,1);
// deal(1);
Build(1,n,1);
cin>>q;
int LCA;
for(int i = 0;i < q; i++){
scanf("%s",opr);
if(opr[0] == 'Q'){
scanf("%d%d",&a,&b);
LCA = lca(a,b);
if(opr[1] == 'M') ans = op1(LCA,a,b);
else ans = op2(LCA,a,b);
printf("%lld\n",ans);
}
else{
scanf("%d%d",&a,&b);
update(w[a],b,1);
}
}
return 0;
}
加上一组数据
14
1 2
2 5
2 6
6 11
6 12
1 3
3 7
1 4
4 8
4 9
9 13
13 14
4 10
5 9 7 1 13 10 8 6 2 5 11 12 3 4
8
QMAX 11 12
QSUM 11 12
QSUM 5 10
QMAX 5 10
QMAX 11 14
QSUM 11 14
QMAX 11 5
QSUM 11 5