BZOJ-2588-Count-on-a-tree-SPOJ10628-LCA+主席树
生活随笔
收集整理的這篇文章主要介紹了
BZOJ-2588-Count-on-a-tree-SPOJ10628-LCA+主席树
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
描述
給定一棵N個節點的樹,每個點有一個權值,對于M個詢問(u,v,k),你需要回答u xor lastans和v這兩個節點間第K小的點權。其中lastans是上一個詢問的答案,初始為0,即第一個詢問的u是明文。
分析
- 想用樹鏈剖分但是發現不知道怎么套主席樹.
- 正解是LCA, 只要維護根節點到每個結點u的權值線段樹. 因為主席樹求第k大支持減法, 所以最終答案就是線段樹 u+v-lca(u,v)-fa[lca(u,v)] 中的第k大.
- 調了半天發現在用lower_bound查找離散后的權值時, unique后的T數組有序不假但重復元素被挪到了數組尾, 所以不能再用原來的T+n+1作為二分查找的上界了.
#include #include #include using namespace std;const int maxn = 100000 + 10; const int maxm = 3000000; const int DEP = 20;vectorG[maxn];int n, m, tot, node_cnt; int A[maxn], T[maxn]; int dep[maxn], fa[maxn][DEP]; int root[maxm], lc[maxm], rc[maxm], s[maxm];#define M (L+R>>1)void modify(int& x, int y, int L, int R, int d) {x = ++node_cnt;lc[x] = lc[y]; rc[x] = rc[y]; s[x] = s[y] + 1;if(L == R) return;if(d <= M) modify(lc[x], lc[y], L, M, d);else modify(rc[x], rc[y], M+1, R, d); }int query(int u, int v, int x, int y, int L, int R, int k) {if(L == R) return L;int ls = s[lc[u]] + s[lc[v]] - s[lc[x]] - s[lc[y]];if(k <= ls) return query(lc[u], lc[v], lc[x], lc[y], L, M, k);return query(rc[u], rc[v], rc[x], rc[y], M+1, R, k-ls); }void dfs(int u, int x) {dep[u] = dep[fa[u][0] = x] + 1;for(int i = 1; i < DEP; i++)if((1<<= dep[u]) fa[u][i] = fa[fa[u][i-1]][i-1]; else break; modify(root[u], root[x], 1, tot, A[u]); for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v != x) dfs(v, u); } } int lca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); int delta = dep[x]-dep[y]; for(int i = 0; i < DEP; i++) if(delta&(1<= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; return fa[x][0]; } int main() { int n, m; scanf("%d %d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d", &A[i]); T[i] = A[i]; } sort(T+1, T+n+1); tot = unique(T+1, T+n+1) - T-1; for(int i = 1; i <= n; i++) A[i] = lower_bound(T+1, T+tot+1, A[i]) - T; for(int i = 1; i < n; i++) { int u, v; scanf("%d %d", &u, &v); G[u].push_back(v); G[v].push_back(u); } dfs(1, 0); int ans = 0; for(int i = 1; i <= m; i++) { int u, v, k; scanf("%d %d %d", &u, &v, &k); u ^= ans; int x = lca(u, v), y = fa[x][0]; ans = T[query(root[u], root[v], root[x], root[y], 1, tot, k)]; if(i < m) printf("%d\n", ans); else printf("%d", ans); } return 0; }
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的BZOJ-2588-Count-on-a-tree-SPOJ10628-LCA+主席树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ-1878-HH的项链-SDOI
- 下一篇: BZOJ-3289-Mato的文件管理-