题目链接: http://vjudge.net/problem/SPOJ-QTREE
题目大致意思就是: 给你一棵树,有连个操作:
● 第一个是查询任意两个不同节点上的最短路径上的最大权边!
● 第二个操作修改某一条边的权值;
对于一棵树,数的深度如果很大,那么每次查询两个叶子节点,时间复杂度还是很高的。所以我们就把树分成一条一条的树链,所谓树链就是:沿着树的一条路径。 得到路径后,我们可以用堆,线段树进行维护。在一些题目中,树链剖分题目,一般可以用dfs 进行剖链。
鄙人学习树链剖分所用到资料:
ACdreams 大神博客 ,看这篇博客主要知道什么是树链剖分,以及原理;知道树链剖分部分,剖分树链之后需要用一些数据结构维护,大部分用线段树。线段树比较常用。所以我也用线段树;
如果觉得博客看着费劲,还是不知道原理是什么的话,可以尝试看看 UESTCACM 每周算法讲堂 dfs序与树链剖分
有了以上知识储备,做这个题目也比较轻松! 线段树要会!!可以参考kuangbin题解来做;附上我AC代码,一是为了存个模板,二还请大佬指出错误!
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<deque>
#include<stack>
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<time.h>
using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAXSIZE=2e4+100;
const double eps=0.0000000001;
void fre()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
}
#define memst(a,b) memset(a,b,sizeof(a))
#define fr(i,a,n) for(int i=a;i<n;i++)
int son[MAXSIZE],deep[MAXSIZE],father[MAXSIZE],num[MAXSIZE],top[MAXSIZE],p[MAXSIZE],fp[MAXSIZE],pos;
int Treevalue[MAXSIZE];
// son 代表重儿子; deep 深度;father 父亲节点;num 统计节点个数;
//top 树链的头, p 某个节点在线段树的位置 ; fp 线段树某个位置在树中的位置;
//pos 是用来对树的节点进行标号的;
// 建图部分
int first[MAXSIZE],ntot;
struct Node
{
int to,next,val;
};
struct NODE
{
int a,b,c;
} input[MAXSIZE];
Node edge[MAXSIZE];
void init()
{
memst(first,-1);
memst(son,-1);
pos=ntot=0;
}
void addedge(int s,int t,int val)
{
edge[ntot].to=t,edge[ntot].val=val;
edge[ntot].next=first[s],first[s]=ntot++;
}
// 剖分树链
void dfs(int x,int pre,int _deep)
{
deep[x]=_deep;
father[x]=pre;
num[x]=1;
for(int i=first[x]; i!=-1; i=edge[i].next)
{
int to=edge[i].to;
if(to!=pre)
{
Treevalue[to]=edge[i].val;
dfs(to,x,_deep+1);
num[x]+=num[to];
if(son[x]==-1||num[to]>num[son[x]]) son[x]=to;
}
}
return ;
}
void getlist(int x,int pr)
{
top[x]=pr;
if(son[x]!=-1) // 如果存在重儿子,就沿着一直找下去
{
p[x]=pos++;
fp[p[x]]=x;
getlist(son[x],pr);
}
else //直到到低端为止
{
p[x]=pos++;
fp[p[x]]=x;
return ;
}
for(int i=first[x]; i!=-1; i=edge[i].next)
{
int to=edge[i].to;
if(to!=son[x]&&to!=father[x]) getlist(to,to); //如果不是往回走 且 不是重儿子那么就是新的树链进行dfs金合欢花;
}
}
//树链剖分部分 完成
// 线段树部分
struct TreeNode
{
int l,r,max;
} tree[MAXSIZE*3];
void push_up(int i)
{
tree[i].max=max(tree[i<<1].max,tree[i<<1|1].max);
}
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r,tree[i].max=0;
if(l==r)
{
tree[i].max=Treevalue[fp[l]];
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
push_up(i);
}
int query(int i,int l,int r)
{
if(tree[i].l==l&&tree[i].r==r) return tree[i].max;
int mid=(tree[i].l+tree[i].r)>>1;
if(l>mid) return query(i<<1|1,l,r);
else if(r<=mid) return query(i<<1,l,r);
else return max(query(i<<1|1,mid+1,r),query(i<<1,l,mid));
}
int getmax(int a,int b)
{
int res=0;
int f1=top[a],f2=top[b];
while(f1!=f2)
{
if(deep[f1]>deep[f2])
{
res=max(res,query(1,p[f1],p[a]));
a=father[f1],f1=top[a];
}
else
{
res=max(res,query(1,p[f2],p[b]));
b=father[f2],f2=top[b];
}
}
if(a==b) return res;
if(deep[a]>deep[b]) swap(a,b);
return max(res,query(1,p[son[a]],p[b]));
}
void update(int i,int k,int val)//插点
{
if(tree[i].l==k&&tree[i].r==k)
{
tree[i].max=val;
return ;
}
int mid=(tree[i].l+tree[i].r)>>1;
if(k>mid) update(i<<1|1,k,val);
else update(i<<1,k,val);
push_up(i);
}
void Debug(int i,int l,int r)
{
if(tree[i].r>r||tree[i].l<l) return ;
printf("i=%d l=%d r=%d max=%d\n",i,tree[i].l,tree[i].r,tree[i].max);
Debug(i<<1,l,r);
Debug(i<<1|1,l,r);
}
int main()
{
int ncase,n;
scanf("%d",&ncase);
while(ncase--)
{
init();
scanf("%d",&n);
for(int i=1; i<n; i++)
{
scanf("%d%d%d",&input[i].a,&input[i].b,&input[i].c);
addedge(input[i].a,input[i].b,input[i].c);
addedge(input[i].b,input[i].a,input[i].c);
}
dfs(1,0,0);//把图变成一棵树;
getlist(1,1);//剖树链;
build(1,1,n-1);
while(1)
{
char opt[10];
scanf("%s",opt);
if(opt[0]=='D') break;
if(opt[0]=='C')
{
int change_pos,value;
scanf("%d%d",&change_pos,&value);
int a=input[change_pos].a,b=input[change_pos].b;
if(deep[a]>deep[b]) swap(a,b);
update(1,p[b],value);
}
else
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",getmax(a,b));
}
}
}
return 0;
}
/**************************************************/
/** Copyright Notice **/
/** writer: wurong **/
/** school: nyist **/
/** blog : http://blog.csdn.net/wr_technology **/
/**************************************************/