spoj 375
题目:http://www.spoj.com/problems/QTREE/
题目大意:给你一棵有N个结点的树,执行两种操作:(1)CHANGE a b,把某一条树枝上的权值改为b。(2)QUERY a b,询问a到b的路径上最大的权值是多少。
思路:继上一道 Free tour 之后漆子超论文里的第三道例题,上两道是点,这次是用的是树链剖分,具体解题思想,可以看漆子超的论文。
如果单独纯模拟,虽然期望复杂度是O(logN),但是最坏情况下会达到O(N),大量询问下,肯定会TLE。引入树链剖分,他有三个性质(具体看论文),用线段数进行维护,复杂度可以降为O(logN*logN)。
转载的上一篇文章是介绍树链剖分的,写的很好,至少简单易懂。。 = = ,就是我感觉那篇文章的有一个地方写错了,就是w[ u ]指的是 u 的父边的权值,那么,根节点的 w 应该是不存在的,如果设边在线段树上的编号从1开始,那么w[ root ] 应该为0,而他写得程序里是1(目前我是这么认为的,毕竟现在自己也不是很懂)。第一次做树链剖分的题,第一遍TLE,发现是有个小地方写错了,改过来后,就AC了,好开心!
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int INF = 0x0fffffff ;
const int MAXN = 11111 ;
struct Edge
{
int t,len,next;
} edge[MAXN<<1];
int head[MAXN],tot;
void add_edge(int s,int t,int len)
{
edge[tot].t=t;
edge[tot].len = len;
edge[tot].next = head[s];
head[s] = tot++;
}
struct Edge_id
{
int a,b,len;
} edge_id[MAXN];
int node[MAXN<<2];
int father[MAXN],dep[MAXN],num[MAXN],son[MAXN],top[MAXN],w[MAXN];
int tot_w;
void dfs(int u,int fa,int level)
{
dep[u] = level;
father[u]=fa;
num[u]=1;
son[u]=-1;
int maxx=0;
for(int e = head[u];e!=-1;e=edge[e].next)
{
int v = edge[e].t;
if(v!=fa)
{
dfs(v,u,level+1);
num[u]+=num[v];
if(num[v]>maxx)
{
maxx = num[v];
son[u]=v;
}
}
}
}
void build(int u,int tp)
{
w[u] = ++tot_w;
top[u]=tp;
if(son[u]!=-1)
build(son[u],tp);
for(int e = head[u];e!=-1;e =edge[e].next)
{
int v = edge[e].t;
if(v!=father[u]&&v!=son[u])
build(v,v);
}
}
void update(int l,int r,int rt,int pos,int c)
{
if(l==r)
{
node[rt]=c;
return ;
}
int m = l+r>>1;
if(pos<=m) update(lson,pos,c);
else update(rson,pos,c);
node[rt] = max(node[rt<<1],node[rt<<1|1]);
}
int query(int l,int r,int rt,int a,int b)
{
if(a<=l&&b>=r)
return node[rt];
int m = l+r>>1;
int cnt1=-INF,cnt2=-INF;
if(a<=m)
cnt1 = query(lson,a,b);
if(b>m)
cnt2 = query(rson,a,b);
return max(cnt1,cnt2);
}
int find(int a,int b)
{
int fa = top[a];
int fb = top[b];
int tmp =0 ;
while(fa!=fb)
{
if(dep[fa]>dep[fb])
{
swap(a,b);
swap(fa,fb);
}
tmp = max(tmp,query(1,tot_w,1,w[fb],w[b]));
b = father[fb];
fb = top[b];
}
if(a==b) return tmp;
if(dep[a]>dep[b])
{
swap(a,b);
}
return max(tmp,query(1,tot_w,1,w[son[a]],w[b]));
}
int n;
void init()
{
int root =1;
dfs(root,root,1);
tot_w = -1;
build(root,root);
for(int i=1;i<n;i++)
{
if(dep[edge_id[i].a]>dep[edge_id[i].b])
swap(edge_id[i].a,edge_id[i].b);
update(1,tot_w,1,w[edge_id[i].b],edge_id[i].len);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int a,b,c;
tot=0;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
edge_id[i].a=a;
edge_id[i].b=b;
edge_id[i].len=c;
}
init();
char str[11];
while(1)
{
scanf("%s",str);
if(str[0]=='D')
break;
int a,b;
scanf("%d%d",&a,&b);
if(str[0]=='C')
{
int va = edge_id[a].a;
int vb = edge_id[a].b;
if(dep[va]>dep[vb])
swap(va,vb);
update(1,tot_w,1,w[vb],b);
}
else printf("%d\n",find(a,b));
}
}
return 0;
}