SPOJ QTREE3 Query on a tree again! 树链剖分
来源:互联网 发布:php 输出文本文件乱码 编辑:程序博客网 时间:2024/06/01 07:24
题目:
https://vjudge.net/problem/SPOJ-QTREE3
题意:
给定一棵树,初始树上的每个点都为白色,有以下操作:
0 i: 把第i个点的颜色取反,白变黑,黑变白1 v: 求从点1到点v的路径上第一个颜色为黑的点
思路:
树链剖分,每次优先查询左子区间,再查询右子区间。因为一定是从
#include <bits/stdc++.h>using namespace std;const int N = 100000 + 10;struct edge{ int to, next;} g[N*2];int cnt, head[N];int dep[N], siz[N], son[N], fat[N], id[N], top[N];int num;int rid[N];struct node{ int l, r, sum;} tr[N*4];void init(){ cnt = 0; memset(head, -1, sizeof head); num = 0;}void add_edge(int v, int u){ g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}void dfs1(int v, int fa, int d){ dep[v] = d, son[v] = 0, siz[v] = 1, fat[v] = fa; for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u != fa) { dfs1(u, v, d + 1); siz[v] += siz[u]; if(siz[son[v]] < siz[u]) son[v] = u; } }}void dfs2(int v, int tp){ top[v] = tp, id[v] = ++num; if(son[v]) dfs2(son[v], top[v]); for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u != fat[v] && u != son[v]) dfs2(u, u); }}void push_up(int k){ tr[k].sum = tr[k<<1].sum + tr[k<<1|1].sum;}void build(int l, int r, int k){ tr[k].l = l, tr[k].r = r, tr[k].sum = 0; if(l == r) { tr[k].sum = 0; return; } int mid = (l + r) >> 1; build(l, mid, k << 1); build(mid + 1, r, k << 1|1); push_up(k);}void update(int x, int k){ if(tr[k].l == tr[k].r) { tr[k].sum ^= 1; return; } int mid = (tr[k].l + tr[k].r) >> 1; if(x <= mid) update(x, k << 1); else update(x, k << 1|1); push_up(k);}int query(int l, int r, int k){ if(tr[k].sum == 0) return 0; if(tr[k].l == tr[k].r) return tr[k].l; int mid = (tr[k].l + tr[k].r) >> 1; int ans = 0; if(l <= mid) ans = query(l, r, k << 1); if(ans) return ans; if(r > mid) ans = query(l, r, k << 1|1); return ans;}int Query(int v, int u){ int t1 = top[v], t2 = top[u]; int ans = 0, tmp = 0; while(t1 != t2) { if(dep[t1] < dep[t2]) swap(t1, t2), swap(v, u); tmp = query(id[t1], id[v], 1); if(tmp) ans = tmp; v = fat[t1], t1 = top[v]; } if(dep[v] > dep[u]) swap(v, u); tmp = query(id[v], id[u], 1); if(tmp) ans = tmp; return ans;}int main(){ int n, m, x, y; while(~ scanf("%d%d", &n, &m)) { init(); for(int i = 1; i <= n-1; i++) { scanf("%d%d", &x, &y); add_edge(x, y); add_edge(y, x); } dfs1(1, 0, 1); dfs2(1, 1); build(1, num, 1); for(int i = 1; i <= n; i++) rid[id[i]] = i; for(int i = 1; i <= m; i++) { scanf("%d%d", &x, &y); if(x == 0) update(id[y], 1); else { int ans = Query(x, y); printf("%d\n", ans ? rid[ans] : -1); } } } return 0;}
另外一种写法, 只有在线段树部分不太一样
#include <bits/stdc++.h>using namespace std;const int N = 100000 + 10;struct edge{ int to, next;} g[N*2];int cnt, head[N];int dep[N], siz[N], son[N], fat[N], id[N], top[N];int rid[N];int num;struct node{ int l, r, val, idx;} tr[N*4];void init(){ cnt = 0; memset(head, -1, sizeof head); num = 0;}void add_edge(int v, int u){ g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;}void dfs1(int v, int fa, int d){ dep[v] = d, son[v] = 0, siz[v] = 1, fat[v] = fa; for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u != fa) { dfs1(u, v, d + 1); siz[v] += siz[u]; if(siz[son[v]] < siz[u]) son[v] = u; } }}void dfs2(int v, int tp){ top[v] = tp, id[v] = ++num; if(son[v]) dfs2(son[v], top[v]); for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u != fat[v] && u != son[v]) dfs2(u, u); }}void push_up(int k){ if(tr[k<<1].val) tr[k].val = tr[k<<1].val, tr[k].idx = tr[k<<1].idx; else tr[k].val = tr[k<<1|1].val, tr[k].idx = tr[k<<1|1].idx;}void build(int l, int r, int k){ tr[k].l = l, tr[k].r = r, tr[k].val = 0; if(l == r) { tr[k].val = 0; return; } int mid = (l + r) >> 1; build(l, mid, k << 1); build(mid + 1, r, k << 1|1); push_up(k);}void update(int x, int k){ if(tr[k].l == tr[k].r) { tr[k].val ^= 1; if(tr[k].val) tr[k].idx = rid[tr[k].l]; else tr[k].idx = 0; return; } int mid = (tr[k].l + tr[k].r) >> 1; if(x <= mid) update(x, k << 1); else update(x, k << 1|1); push_up(k);}int query(int l, int r, int k){ if(tr[k].val == 0) return 0; if(l <= tr[k].l && tr[k].r <= r) return tr[k].idx; int mid = (tr[k].l + tr[k].r) >> 1; int ans = 0; if(l <= mid) ans = query(l, r, k << 1); if(ans) return ans; if(r > mid) ans = query(l, r, k << 1|1); return ans;}int Query(int v, int u){ int t1 = top[v], t2 = top[u]; int ans = -1, tmp = 0; while(t1 != t2) { if(dep[t1] < dep[t2]) swap(t1, t2), swap(v, u); tmp = query(id[t1], id[v], 1); if(tmp) ans = tmp; v = fat[t1], t1 = top[v]; } if(dep[v] > dep[u]) swap(v, u); tmp = query(id[v], id[u], 1); if(tmp) ans = tmp; return ans;}int main(){ int n, m, x, y; while(~ scanf("%d%d", &n, &m)) { init(); for(int i = 1; i <= n-1; i++) { scanf("%d%d", &x, &y); add_edge(x, y); add_edge(y, x); } dfs1(1, 0, 1); dfs2(1, 1); build(1, num, 1); for(int i = 1; i <= n; i++) rid[id[i]] = i; for(int i = 1; i <= m; i++) { scanf("%d%d", &x, &y); if(x == 0) update(id[y], 1); else printf("%d\n", Query(x, y)); } } return 0;}
阅读全文
0 0
- spoj QTREE3 Query on a tree again!
- SPOJ QTREE3 Query on a tree again! 树链剖分
- 动态树LCT||树链剖分+线段树(SPOJ QTREE3 - Query on a tree again!)
- spoj2798 QTREE3 Query on a tree again!
- spoj Query on a tree again(树链剖分)
- [SPOJ 375]Query On a Tree(树链剖分)
- SPOJ 375. Query on a tree【树链剖分】
- SPOJ 375. Query on a tree【树链剖分】
- SPOJ QTREE(Query on a tree树链剖分)
- spoj 375--Query On a Tree [树链剖分]
- spoj 375 Query on a tree 树链剖分
- spoj 375. Query on a tree(树链剖分)
- SPOJ QTREE Query on a tree --树链剖分
- [ SPOJ - QTREE]Query on a tree && 树链剖分
- SPOJ Query on a tree (树链剖分)
- SPOJ QTREE Query on a tree 树链剖分
- SPOJ QTREE Query on a tree 树链剖分
- 【树链剖分】[SPOJ-QTREE]Query on a tree
- MySQL(八)之DML
- SVN之使用之注意要点
- oracle数据库合并行记录,WMSYS.WM_CONCAT函数的用法
- 【JS】类型检测
- MySQL总结—基础篇(一)
- SPOJ QTREE3 Query on a tree again! 树链剖分
- Android_webview之加载网页
- elasticsearch-kibanna 查询札记
- 数据流图
- python-Pandas学习 如何对数据集随机抽样?
- 私有云API接口
- Michael Nielsen的神经网络与深度学习入门教程
- Swift 中的扩展 (Extension)
- 深入mysql insert table ... "ON DUPLICATE KEY UPDATE" 语法的分析