You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1.
We will ask you to perfrom some instructions of the following form:
The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.
For each test case:
There is one blank line between successive tests.
For each "QUERY" operation, write one integer representing its result.
Input: 1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE Output: 1 3
大致题意:一棵1e4节点的树,进行两种操作,1.把第i条边权值改为x 2.查询a到b路径上的最大边权
树链剖分教程http://blog.sina.com.cn/s/blog_7a1746820100wp67.html
学了树链剖分,这种算法是把树hash到了几段连续的区间上,分重链和轻链为连续的区间,可以证明任何两点间路径都可以分为logn复杂度的重链和轻链,也就是连续区间,然后再用线段树等算法在这些区间上处理问题
显然本题也是这样,剖分过程On复杂度,两次dfs,用在logn的复杂度套上线段树nlogn,总复杂度是nlogn*logn
14620018 | 2015-07-07 17:10:34 | ka | Query on a tree | acceptededit ideone it | 0.44 | 3.9M | C++ 4.9 |
#include <iostream> #include <cstring> #include <cmath> #include <queue> #include <stack> #include <list> #include <map> #include <set> #include <sstream> #include <string> #include <vector> #include <cstdio> #include <ctime> #include <bitset> #include <algorithm> #define SZ(x) ((int)(x).size()) #define ALL(v) (v).begin(), (v).end() #define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i) #define refeach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i) #define REP(i,n) for ( int i=1; i<=int(n); i++ ) using namespace std; typedef long long ll; const int N = 1e4+100; struct Edge { int u,v,w,nxt; Edge(){} Edge(int u,int v,int w,int nxt) : u(u),v(v),w(w),nxt(nxt) {} }es[N<<1]; int head[N]; int ecnt; int n; inline void add_edge(int u,int v,int w) { es[++ecnt] = Edge(u,v,w,head[u]); head[u] = ecnt; es[ecnt+n] = Edge(v,u,w,head[v]); head[v] = ecnt+n; } int dep[N],son[N],sz[N],fa[N]; void dfs1(int u) { dep[u] = dep[fa[u]]+1; son[u] = 0,sz[u] = 1; for(int i = head[u];~i;i=es[i].nxt) { int v = es[i].v; if(fa[u] == v) continue; fa[v] = u; dfs1(v); sz[u] += sz[v]; if(sz[v] > sz[son[u]]) son[u] = v; } } int tp[N],tid[N]; int indx; void dfs2(int u,int ance) { tid[u] = ++indx; tp[u] = ance; if(son[u]) dfs2(son[u],ance); for(int i = head[u];~i;i=es[i].nxt) { int v = es[i].v; if(v == fa[u]) continue; if(v != son[u]) dfs2(v,v); } } #define root 1,indx,1 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int maxn[N<<2]; inline void pushup(int rt) { maxn[rt] = max(maxn[rt<<1],maxn[rt<<1|1]); } void update(int pos,int x,int l,int r,int rt) { if(l == r) { maxn[rt] = x; return ; } int m = (l+r)>>1; if(pos <= m) update(pos,x,lson); else update(pos,x,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt) { if(L <= l && r <= R) return maxn[rt]; int maxx = 0; int m = (l+r)>>1; if(L <= m) maxx = max(maxx,query(L,R,lson)); if(R >= m+1) maxx = max(maxx,query(L,R,rson)); return maxx; } int solve(int u,int v) { int anceu = tp[u],ancev = tp[v]; int maxx = 0; while(anceu != ancev) { if(dep[anceu] < dep[ancev]) swap(anceu,ancev),swap(u,v); maxx = max(maxx,query(tid[anceu],tid[u],root)); u = fa[anceu]; anceu = tp[u]; } if(u == v) return maxx; if(dep[u] < dep[v]) return max(maxx,query(tid[son[u]],tid[v],root)); else return max(maxx,query(tid[son[v]],tid[u],root)); } void ini() { memset(head,-1,sizeof(head)); indx = ecnt = 0; memset(maxn,0,sizeof(maxn)); } int main() { int T; scanf("%d",&T); while(T--) { ini(); scanf("%d",&n); REP(i,n-1) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add_edge(u,v,w); } char op[20]; dfs1(1); dfs2(1,1); REP(i,n-1) { int u = es[i].u,v = es[i].v , w = es[i].w; if(dep[v] < dep[u]) swap(es[i].u,es[i].v); update(tid[es[i].v],w,root); } while(scanf("%s",op)) { if(op[0] == 'D') break; if(op[0] == 'Q') { int u,v; scanf("%d%d",&u,&v); printf("%d\n",solve(u,v)); } else { int id,x; scanf("%d%d",&id,&x); update(tid[es[id].v],x,root); } } } }