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; }