http://www.spoj.pl/problems/QTREE/
给一颗树,每条边有一个权值。有两种操作:1、修改某条边的值;2、询问a、b两点路径上边权的最大值。
树链剖分。
#include <cstdio> #include <algorithm> #include <iostream> #include <string.h> using namespace std; #define maxn 100100 #define lson (pos<<1) #define rson (pos<<1|1) //-----------------------------------建边部分------------------------- int cnt, head[maxn]; struct Edge { int to,next; }e[maxn*3]; void Add_edge(int a, int b) { e[cnt].to=b; e[cnt].next=head[a]; head[a]=cnt++; } //-----------------------------------树链部分------------------------- //记siz[v]表示以v为根的子树的节点数,dep[v]表示v的深度(根深度为1) //top[v]表示v所在的链的顶端节点,fa[v]表示v的父亲 //son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子) //ti[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置 int son[maxn], top[maxn], sz[maxn], dep[maxn], fa[maxn], ti[maxn], dfs_clock; int n,m; void dfs_find(int u, int pa, int depth) { son[u]=0;sz[u]=1;dep[u]=depth;fa[u]=pa; for(int i = head[u]; i != -1; i = e[i].next) { int v=e[i].to; if(v==pa)continue; dfs_find(v,u,depth+1); sz[u]+=sz[v]; if(sz[v]>sz[son[u]])son[u]=v; } } void dfs_time(int u, int pa) { ti[u]=++dfs_clock; top[u]=pa; if(son[u]!=0)dfs_time(son[u],top[u]); for(int i = head[u]; i != -1; i = e[i].next) if(e[i].to!=son[u]&&e[i].to!=fa[u]) dfs_time(e[i].to, e[i].to); } //-----------------------------------线段树部分------------------------- struct node { int l,r,val,mx; int mid(){return (l+r)>>1;} }tree[maxn<<2]; void build(int pos, int l, int r) { tree[pos].l=l;tree[pos].r=r;tree[pos].mx=tree[pos].val=-0x7ffffff; if(l==r)return ; int mid=tree[pos].mid(); build(lson,l,mid); build(rson,mid+1,r); } void update(int pos, int id, int w) { if(tree[pos].l==tree[pos].r) { tree[pos].mx=tree[pos].val=w; return ; } int mid=tree[pos].mid(); if(mid>=id)update(lson,id,w); else update(rson,id,w); tree[pos].mx=max(tree[lson].mx,tree[rson].mx); } int query(int pos, int L, int R) { if(L<=tree[pos].l&&tree[pos].r<=R) return tree[pos].mx; int mid=tree[pos].mid(); int ans=-0x7ffffff; if(mid>=L)ans=max(ans, query(lson,L,R)); if(mid<R)ans=max(ans, query(rson,L,R)); return ans; } int lca(int x, int y) //这里传的参数是实际点x和y,不是映射后的点 { int ans=-0x7ffffff; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); ans=max(ans,query(1,ti[top[x]],ti[x])); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); if(x!=y) ans=max(ans,query(1,ti[x]+1,ti[y])); //这里的ti[x]指的是x与其父亲的边,所以一定注意+1 return ans; } void ini() { cnt=dfs_clock=0; memset(head,-1,sizeof(head)); } int da[maxn][3]; int main() { int T;scanf("%d",&T); while(T--) { scanf("%d",&n); ini(); for(int i = 1; i < n; i++) { scanf("%d%d%d",&da[i][0],&da[i][1],&da[i][2]); Add_edge(da[i][0],da[i][1]); Add_edge(da[i][1],da[i][0]); } dfs_find(1,1,1); dfs_time(1,1); build(1,2,n); for(int i = 1; i < n; i++) { if(dep[da[i][0]]>dep[da[i][1]])swap(da[i][0],da[i][1]); update(1,ti[da[i][1]],da[i][2]); } char he[100]; while(1) { scanf("%s",he); if(he[0]=='D')break; if(he[0]=='Q') { int a,b;scanf("%d%d",&a,&b); printf("%d\n",lca(a,b)); } else { int a,b;scanf("%d%d",&a,&b); update(1,ti[da[a][1]],b); } } printf("\n"); } return 0; }