<h2>题目描述</h2>
给定一棵 $ N $ 个节点的树,需要维持以下个操作:
- 改变第 $ k $ 条边的边权;
- 改变点 $ u $ 到点 $ v $ 的边权为 $ w $;
- 将点 $ u $ 和点 $ v $ 路径上的边的边权都增加 $ w $;
- 询问点 $ u $ 和点 $ v $ 路径上的边权最大值。
其中 $ 1 \leq N \leq 10^5 $,操作+询问数目不超过 $ 10^5 $。
<h2>解题报告</h2>
这显然是树链剖分板子题。
不过这里处理的是边权,我们对于每一个边,将边权放在深度更大的点上。
然后查询的时候特判 LCA 情况(因为 LCA 不被计算)就可以了。
操作一:线段树直接找这条边深度更深的点并修改。
剩余操作全都特判 LCA 情况即可,具体可参考代码。
<h2>代码</h2>
我就知道你们想看这个
#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdio>
const int MAXN = 100000 + 5;
int N;
struct Data{
int u,v,w;
}e[MAXN];
struct Node{
struct Edge *firstEdge;
struct Chain *chain;
Node fa,maxChild;
int size,dfn,depth;
bool vis;
}node[MAXN];
struct Edge{
Node s,t;
Edge *next;
}pool1[MAXN 2],frog1 = pool1;
Edge New1(Node s,Node *t){
Edge *ret = ++frog1;
ret->s = s;ret->t = t;
ret->next = s->firstEdge;
return ret;
}
inline void add(int u,int v){
node[u].firstEdge = New1(&node[u],&node[v]);
node[v].firstEdge = New1(&node[v],&node[u]);
}
struct Chain{
Node *top;
}pool2[MAXN],*frog2 = pool2;
Chain New2(Node top){
Chain *ret = ++frog2;
ret->top = top;
return ret;
}
void dfs1(Node *v){
v->size = 1;v->vis = true;
for(Edge *e = v->firstEdge;e;e = e->next){
if(e->t->vis) continue;
e->t->fa = v;
e->t->depth = v->depth + 1;
dfs1(e->t);
v->size += e->t->size;
if(!v->maxChild || v->maxChild->size < e->t->size)
v->maxChild = e->t;
}
}
void dfs2(Node *v){
static int ts = 0;
v->dfn = ++ts;
if(!v->fa || v->fa->maxChild != v) v->chain = New2(v);
else v->chain = v->fa->chain;
if(v->maxChild)
dfs2(v->maxChild);
for(Edge *e = v->firstEdge;e;e = e->next){
if(v->maxChild != e->t && e->t->fa == v)
dfs2(e->t);
}
}
inline void split(int root){
node[root].depth = 1;
dfs1(&node[root]);
dfs2(&node[root]);
}
struct SegmentTree;
SegmentTree New3(int ,int ,SegmentTree ,SegmentTree *);
struct SegmentTree{
int l,r,max,tag1,tag2; // tag1 = delta,tag2 = modify
SegmentTree lc,rc;
static SegmentTree *build(int l,int r){
int mid = (l + r) >> 1;
return (l == r) ? New3(l,r,NULL,NULL) : New3(l,r,build(l,mid),build(mid + 1,r));
}
inline void pushup(){
max = std::max(lc->max,rc->max);
}
inline void cover1(int delta){ // delta
max += delta;
tag1 += delta;
}
inline void cover2(int delta){ // modify
max = delta;
tag2 = delta;
tag1 = 0;
}
inline void pushdown(){ // ???
if(tag2 != -1){
lc->cover2(tag2);
rc->cover2(tag2);
lc->tag1 = rc->tag1 = 0;
tag2 = -1;
}
if(tag1){
lc->cover1(tag1);
rc->cover1(tag1);
tag1 = 0;
}
}
inline void update(int pos,int x){
if(l == r){
max = x;tag1 = tag2 = 0;return;
}
pushdown();
int mid = (l + r) >> 1;
if(pos <= mid) lc->update(pos,x);
else rc->update(pos,x);
pushup();
}
void modify1(int left,int right,int delta){ // delta
if(l == left && r == right){
cover1(delta);return;
}
pushdown();
int mid = (l + r) >> 1;
if(right <= mid) lc->modify1(left, right, delta);
else if(left > mid) rc->modify1(left, right, delta);
else{
lc->modify1(left, mid, delta);
rc->modify1(mid + 1, right, delta);
}
pushup();
}
void modify2(int left,int right,int delta){ // modi
if(l == left && r == right){
cover2(delta);return;
}
pushdown();
int mid = (l + r) >> 1;
if(right <= mid) lc->modify2(left, right, delta);
else if(left > mid) rc->modify2(left, right, delta);
else{
lc->modify2(left,mid,delta);
rc->modify2(mid + 1,right,delta);
}
pushup();
}
int query(int left,int right){
if(l == left && r == right) return max;
// if(right < l || left > r) return INT_MIN;
pushdown();
int mid = (l + r) >> 1;
if(right <= mid) return lc->query(left,right);
if(left > mid) return rc->query(left, right);
return std::max(lc->query(left,mid),rc->query(mid + 1,right));
}
}pool3[MAXN4],frog3 = pool3,*segt;
SegmentTree New3(int l,int r,SegmentTree lc,SegmentTree *rc){
SegmentTree *ret = ++frog3;
ret->l = l;ret->r = r;
ret->lc = lc;ret->rc = rc;
ret->max = INT_MIN;
ret->tag1 = 0;ret->tag2 = -1;
return ret;
}
Node *lca(int x,int y){
Node u = &node[x],v = &node[y];
while(u->chain != v->chain){
if(u->chain->top->depth < v->chain->top->depth) std::swap(u,v);
u = u->chain->top->fa;
}
if(u->depth > v->depth) std::swap(u,v);
return u;
}
inline void Change(int pos,int x){
// segt->update(node[e[pos].u].dfn,x);
int u = node[e[pos].u].depth > node[e[pos].v].depth ? e[pos].u : e[pos].v;
segt->update(node[u].dfn,x);
}
inline void Cover_Point(int x,int y,int delta){
Node u = &node[x],v = &node[y];
while(u->chain != v->chain){
if(u->chain->top->depth < v->chain->top->depth) std::swap(u,v);
segt->modify2(u->chain->top->dfn,u->dfn,delta);
u = u->chain->top->fa;
}
if(u->depth > v->depth) std::swap(u,v);
segt->modify2(u->dfn,v->dfn,delta);
}
inline void Cover(int x,int y,int delta){
Node *l = lca(x,y);
int last = segt->query(l->dfn,l->dfn);
Cover_Point(x,y,delta);
segt->update(l->dfn,last);
}
inline void Add_Point(int x,int y,int delta){
Node u = &node[x],v = &node[y];
while(u->chain != v->chain){
if(u->chain->top->depth < v->chain->top->depth) std::swap(u,v);
segt->modify1(u->chain->top->dfn,u->dfn,delta);
u = u->chain->top->fa;
}
if(u->depth > v->depth) std::swap(u,v);
segt->modify1(u->dfn,v->dfn,delta);
}
inline void Add(int x,int y,int delta){
Node *l = lca(x,y);
int last = segt->query(l->dfn,l->dfn);
Add_Point(x,y,delta);
segt->update(l->dfn,last);
}
inline int Max_Point(int x,int y){
Node u = &node[x],v = &node[y];
int ret = INT_MIN;
while(u->chain != v->chain){
if(u->chain->top->depth < v->chain->top->depth) std::swap(u,v);
ret = std::max(ret,segt->query(u->chain->top->dfn,u->dfn));
u = u->chain->top->fa;
}
if(u->depth > v->depth) std::swap(u,v);
return std::max(ret,segt->query(u->dfn,v->dfn));
}
inline int Max(int x,int y){
Node *l = lca(x,y);
int last = segt->query(l->dfn,l->dfn);
segt->update(l->dfn,INT_MIN);
int ret = Max_Point(x,y);
segt->update(l->dfn,last);
return ret;
}
int main(){
scanf("%d",&N);
for(int i = 1;i < N;i++){
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
add(e[i].u,e[i].v);
}
split(1);
segt = SegmentTree::build(1,N);
for(int i = 1;i < N;i++){
if(node[e[i].u].depth < node[e[i].v].depth) std::swap(e[i].u,e[i].v);
segt->update(node[e[i].u].dfn,e[i].w);
}
char str[sizeof("Change") + 1];
int x,y,z;
while(str[0] != 'S'){
scanf("%s",str);
if(str[1] == 'h'){
scanf("%d%d",&x,&y);
Change(x,y);
}
if(str[1] == 'o'){
scanf("%d%d%d",&x,&y,&z);
Cover(x,y,z);
}
if(str[1] == 'd'){
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z);
}
if(str[1] == 'a'){
scanf("%d%d",&x,&y);
printf("%dn",Max(x,y));
}
}
return 0;
}