题目链接:http://poj.org/problem?id=3237
Tree
Description
You are given a tree with N N N nodes. The tree’s nodes are numbered 1 1 1 through N N N and its edges are numbered 1 through N − 1 N − 1 N−1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGE
i
v
i\ v
i v Change the weight of the
i
i
i-th edge to
v
v
v
NEGATE
a
b
a\ b
a b Negate the weight of every edge on the path from
a
a
a to
b
b
b
QUERY
a
b
a\ b
a b Find the maximum weight of edges on the path from
a
a
a to
b
b
b
Input
The input contains multiple test cases. The first line of input contains an integer t ( t ≤ 20 ) t (t ≤ 20) t(t≤20), the number of test cases. Then follow the test cases.
Each test case is preceded by an empty line. The first nonempty line of its contains N ( N ≤ 10 , 000 ) N (N ≤ 10,000) N(N≤10,000). The next N − 1 N − 1 N−1 lines each contains three integers a , b a, b a,b and c c c, describing an edge connecting nodes a a a and b b b with weight c c c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.
Output
For each “QUERY” instruction, output the result on a separate line.
Sample Input
1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
Sample Output
1
3
-
题意
给你一颗树,完成如下操作:- CHANGE i v i\ v i v:将输入中的第 i i i条边权值改为 v v v
- NEGATE
a
b
a\ b
a b:将树上从
a
a
a到
b
b
b的简单路径上所有边权取反(
不是变为0) - QUERY a b a\ b a b:询问从 a a a到 b b b的最短路径上的边权最大值
-
题解 ⇒ \Rightarrow ⇒ 树链剖分+线段树
- 锻炼 d e b u g debug debug 好题(除了大佬)
- 树剖出链,然后线段树维护区间被取反了几次
- 线段树同时维护区间最大值和最小值,最小值的用处就是当区间被奇数次取反时,区间最大值更新为最小值的负数
- 而且这题是边权而不是点权,考虑把边权下放到该边所在的链的儿子身上
举个栗子,比如这个图: 1 4 1\ 4 1 4之间的边权 1 1 1放到 4 4 4身上, 4 9 4\ 9 4 9之间的边权 2 2 2放到 9 9 9身上 - 剩下的就只有实现的细节了(树剖代码这么长,所以还是尽量第一次认真写,不然 h h h hhh hhh, d e b u g debug debug到你怀疑 P O J POJ POJ数据错了233 ),由于树剖数组较多,多组数据的情况下记得所有都检查一下是否需要清空
附代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
//存树
struct edge{
int to,id;
edge(int a=0,int b=0){
to=a;id=b;
}
}son[maxn];
vector<edge> vec[maxn];
//树剖用
int h[maxn],fa[maxn],top[maxn],id[maxn],siz[maxn],rk[maxn],ed[maxn],tot;
//题目数据
int t,n,num,u[maxn],v[maxn],a,b;ll val[maxn],c;
char opt[20];
struct node{
int l,r,opt;
ll minn,maxx;
}tree[maxn<<2];
struct segment_tree{
void build(int le,int ri,int id){
tree[id].l=le,tree[id].r=ri;tree[id].opt=0;
if(le==ri) {
tree[id].minn=tree[id].maxx=val[rk[le]];
return;
}
int mid=(le+ri)>>1;
build(le,mid,id<<1);
build(mid+1,ri,id<<1|1);
pushup(id);
}
void pushup(int id){
tree[id].maxx=max(tree[id<<1].maxx,tree[id<<1|1].maxx);
tree[id].minn=min(tree[id<<1].minn,tree[id<<1|1].minn);
}
void down(int id){
tree[id<<1].opt=(tree[id<<1].opt+tree[id].opt)%2;
tree[id<<1|1].opt=(tree[id<<1|1].opt+tree[id].opt)%2;
ll x=tree[id<<1].minn,y=tree[id<<1].maxx;
tree[id<<1].minn=-y;tree[id<<1].maxx=-x;
x=tree[id<<1|1].minn,y=tree[id<<1|1].maxx;
tree[id<<1|1].minn=-y;tree[id<<1|1].maxx=-x;
tree[id].opt=0;
}
int len(int id){
return tree[id].r-tree[id].l+1;
}
void update(int l,int r,int id){
if(l<=tree[id].l&&r>=tree[id].r){
tree[id].opt=(tree[id].opt+1)%2;
ll a=tree[id].minn,b=tree[id].maxx;
tree[id].minn=-b;tree[id].maxx=-a;
return;
}
if(tree[id].opt) down(id);
int mid=(tree[id].l+tree[id].r)>>1;
if(l<=mid) update(l,r,id<<1);
if(r>mid) update(l,r,id<<1|1);
pushup(id);
}
ll query(int l,int r,int id){
ll ans=-1e18;
if(l<=tree[id].l&&r>=tree[id].r) return tree[id].maxx;
if(tree[id].opt) down(id);
int mid=(tree[id].l+tree[id].r)>>1;
if(l<=mid) ans=max(ans,query(l,r,id<<1));
if(r>mid) ans=max(ans,query(l,r,id<<1|1));
pushup(id);
return ans;
}
void modify(int k,int id,ll val){
if(tree[id].l==tree[id].r) {
tree[id].minn=tree[id].maxx=val;
tree[id].opt=0;
return;
}
if(tree[id].opt) down(id);
int mid=(tree[id].l+tree[id].r)>>1;
if(k<=mid) modify(k,id<<1,val);
else modify(k,id<<1|1,val);
pushup(id);
}
}data;
struct tree_{
void init(){
tot=-1;
for(int i=1;i<=n;i++) son[i].id=son[i].to=0;
memset(h,0,sizeof(h));
}
void build(){
dfs1(1,0,1,0);dfs2(1,1,0);
data.build(1,n-1,1);
}
void dfs1(int cur,int fath,int he,int id){ //dfs(root,0,1)
h[cur]=he;fa[cur]=fath;siz[cur]=1;
if(u[id]!=fath) swap(u[id],v[id]);
for(int i=0;i<(int)vec[cur].size();i++){
edge nxt=vec[cur][i];
if(nxt.to!=fath){
dfs1(nxt.to,cur,he+1,nxt.id);
siz[cur]+=siz[nxt.to];
if(siz[nxt.to]>siz[son[cur].to]) son[cur]=nxt;
}
}
}
void dfs2(int cur,int topp,int idd){ //dfs2(root,root)
id[cur]=++tot;rk[tot]=idd;ed[idd]=tot;top[cur]=topp;
if(son[cur].to) dfs2(son[cur].to,topp,son[cur].id);
for(int i=0;i<(int)vec[cur].size();i++){
edge nxt=vec[cur][i];
if(nxt.to!=fa[cur]&&nxt.to!=son[cur].to){
dfs2(nxt.to,nxt.to,nxt.id);
}
}
}
ll query(int x,int y){
int topx=top[x],topy=top[y];ll ans=-1e18;
while(topx!=topy){
if(h[topx]>=h[topy]){
ans=max(ans,data.query(id[topx],id[x],1));
x=fa[topx],topx=top[x];
}else{
ans=max(ans,data.query(id[topy],id[y],1));
y=fa[topy],topy=top[y];
}
}
if(abs(id[x]-id[y])>=1) ans=max(ans,data.query(min(id[x],id[y])+1,max(id[x],id[y]),1));
return ans;
}
void update(int x,int y){
int topx=top[x],topy=top[y];
while(topx!=topy){
if(h[topx]>=h[topy]){
data.update(id[topx],id[x],1);
x=fa[topx],topx=top[x];
}else{
data.update(id[topy],id[y],1);
y=fa[topy],topy=top[y];
}
}
if(abs(id[x]-id[y])>=1) data.update(min(id[x],id[y])+1,max(id[x],id[y]),1);
}
void modify(int x,ll val){
data.modify(ed[x],1,val);
}
}chain;
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d",&n);chain.init();
for(int i=1;i<=n;i++) vec[i].clear();
for(int i=1;i<n;i++){
scanf("%d %d %lld",&u[i],&v[i],&val[i]);
vec[u[i]].push_back(edge(v[i],i));
vec[v[i]].push_back(edge(u[i],i));
}
chain.build();
while(true){
scanf("%s",opt+1);
if(opt[1]=='D') break;
if(opt[1]=='C') {
scanf("%d %lld",&a,&c);
chain.modify(a,c);
}else if(opt[1]=='N'){
scanf("%d %d",&a,&b);
chain.update(a,b);
}else {
scanf("%d %d",&a,&b);
printf("%lld\n",chain.query(a,b));
}
}
}
}