SPOJ375 QTREE 树链剖分入门
2013-12-20 12:17
387 查看
题目链接:http://www.spoj.com/problems/QTREE/
入门资料:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html
专题训练:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#overview
入门资料很详细,细节自己要多想想。
下面说说我的初步理解:
剖分后的树有如下性质:
性质1:如果(v,u)为轻边,则sz[u] * 2 < sz[v];
性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。
性质1是显然的,仔细想想极限情况,不难发现性质2也是成立的。
这里我们关键用到了性质2 让每次单点更新O(log(n)) 查询O(log(n)^2)
查询的时候暴力的做法极限是O(n),也就是两条链的情况,有了轻重链的区分以后,
查询时在重链上是一段一段往上跳的,而暴力只能一条一条往上跳。
注意点:当查询a与b时,为了避免在重链上往上跳的时候跳到了a与b的lca上面,
f1 = top[a], f2 = top[b], 先让往上跳好以后深度大的那个点先跳,假设dep[f1] > dep[f2],
那么先跳f1。跳出while循环后,a与b要么是同一个点,要么就是在同一条重链上。
另:还有一种思路是先求出他们的lca,往上跳的时候做一下判断,
这也是可行的,这样就可以让两个点分开跳,互不影响。
入门资料:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html
专题训练:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#overview
入门资料很详细,细节自己要多想想。
下面说说我的初步理解:
剖分后的树有如下性质:
性质1:如果(v,u)为轻边,则sz[u] * 2 < sz[v];
性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。
性质1是显然的,仔细想想极限情况,不难发现性质2也是成立的。
这里我们关键用到了性质2 让每次单点更新O(log(n)) 查询O(log(n)^2)
查询的时候暴力的做法极限是O(n),也就是两条链的情况,有了轻重链的区分以后,
查询时在重链上是一段一段往上跳的,而暴力只能一条一条往上跳。
注意点:当查询a与b时,为了避免在重链上往上跳的时候跳到了a与b的lca上面,
f1 = top[a], f2 = top[b], 先让往上跳好以后深度大的那个点先跳,假设dep[f1] > dep[f2],
那么先跳f1。跳出while循环后,a与b要么是同一个点,要么就是在同一条重链上。
另:还有一种思路是先求出他们的lca,往上跳的时候做一下判断,
这也是可行的,这样就可以让两个点分开跳,互不影响。
#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 maxn = 10004; struct Edge { int v, w, next; }edge[maxn<<2]; int head[maxn], E; void add(int s, int t, int w) { edge[E] = (Edge) {t, w, head[s]}; head[s] = E++; } void init() { E = 0; memset(head, -1, sizeof(head)); } int n; int top[maxn], fa[maxn], son[maxn];//节点的一些信息 int dep[maxn], sz[maxn]; //节点的一些信息 int sum[maxn<<2], pos[maxn], tot; //线段树部分信息 // pos[i]表示点i与其父亲的连边在线段树中的位置 // tot线段树叶子节点的个数 void dfs(int u) { sz[u] = 1; son[u] = 0; for(int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].v; if(v == fa[u]) continue; dep[v] = dep[u] + 1; fa[v] = u; dfs(v); sz[u] += sz[v]; if(sz[v] > sz[son[u]]) son[u] = v; } } void dfs(int u, int rt) { pos[u] = ++tot; top[u] = rt; if(son[u]) dfs(son[u], rt); for(int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].v; if(v != fa[u] && v != son[u]) dfs(v, v); } } void update(int p, int v, int l, int r, int rt) { if(l == r) { sum[rt] = v; return; } int m = (l + r) >> 1; if(p <= m) update(p, v, lson); else update(p, v, rson); sum[rt] = max(sum[rt<<1], sum[rt<<1|1]); } int query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) return sum[rt]; int ret = 0; int m = (l + r) >> 1; if(L <= m) ret = max(ret, query(L, R, lson)); if(R > m) ret = max(ret, query(L, R, rson)); return ret; } int find(int x, int y) { int fx = top[x], fy = top[y]; int ret = 0; while(fx != fy) { if(dep[fx] < dep[fy]) { swap(fx, fy); swap(x, y); } ret = max(ret, query(pos[fx], pos[x], 1, tot, 1)); x = fa[fx], fx = top[x]; } if(x == y) return ret; //以下为a与b在同一条重链上 if(dep[x] > dep[y]) swap(x, y); //注意a与其父亲的连边不在询问范围内, 所以pos[a]+1 表示 a的重儿子与a的连边在线段树中的位置 ret = max(ret, query(pos[son[x]], pos[y], 1, tot, 1)); return ret; } struct node { int x, y, z; }q[maxn]; int main() { int i, j, cas; scanf("%d", &cas); while(cas--) { scanf("%d", &n); init(); for(i = 1; i < n; i++) { scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].z); add(q[i].x, q[i].y, q[i].z); add(q[i].y, q[i].x, q[i].z); } memset(sum, 0, sizeof(sum));//线段树初始化 tot = 0; dfs(1); dfs(1, 1); for(i = 1; i < n; i++) { if(dep[q[i].x] > dep[q[i].y]) swap(q[i].x, q[i].y); update(pos[q[i].y], q[i].z, 1, tot, 1); } char op[11]; int a, b; while(scanf("%s", op) && op[0] != 'D') { scanf("%d%d", &a, &b); if(op[0] == 'Q') printf("%d\n", find(a, b)); else { update(pos[q[a].y], b, 1, tot, 1); } } } return 0; }
相关文章推荐
- SPOJ 375 QTREE (树链剖分入门题)
- SPOJ 375 QTREE系列-Query on a tree (树链剖分)
- spoj375 Query on a tree(树链剖分 边权 入门题)
- Spoj 375 Qtree 树链剖分 + 线段树 解法
- SPOJ 375 Query on a tree[树链剖分入门]
- SPOJ-375 QTREE - Query on a tree (树链剖分 边权转点权)
- SPOJ 题目 375 QTREE - Query on a tree(树链剖分)
- SPOJ - QTREE Query on a tree ( 树链剖分 入门)
- spoj 375 QTREE - Query on a tree 树链剖分 LCT 动态树
- SPOJ375——Query on a tree(树链剖分模板详解以及入门)
- 树链剖分模板+入门题 SPOJ - QTREE
- SPOJ 375 Query on a tree(树链剖分)(QTREE)
- SPOJ 375 树链剖分 QTREE - Query on a tree
- SPOJ 375 QTREE - Query on a tree 树链剖分+线段树(单点更新 区间查询最值)
- Spoj 375 QTREE1 树链剖分裸题
- Spoj 375 QTREE(树链剖分)
- spoj 375 QTREE - Query on a tree(树链剖分,边权)
- 【SPOJ】375 Query on a tree QTREE系列之1 树链剖分
- SPOJ 375 QTREE Query on a tree 树链剖分
- SPOJ 375 QTREE Query on a tree 树链剖分水题