日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【树链剖分】【倍增】宝石(2021GDOI Day2 T1)

發布時間:2023/12/3 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【树链剖分】【倍增】宝石(2021GDOI Day2 T1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

luogu 7518


題目大意

給你一棵樹,一條路徑的價值為:路徑上點權以1開始依次遞增1的子序列,有q次詢問,每次詢問一條路徑的價值


解題思路

n,m值比較大,對于每次詢問只有O(log2n)O(log^2n)O(log2n)的時間

考慮樹鏈剖分,將詢問分成logloglog

先預處理出uji,j,dji,juj_{i,j},dj_{i,j}uji,j?,dji,j?,分別是當前枚舉到i點,點權為wiw_iwi?,在該重鏈上向上/下跳2j2^j2j個權值跳到的點

那么找到一個起始點后,就可以對這條重鏈進行查詢了

對于起始點,可以對每個權值的點建一個set,因為一條重鏈上的點dfs序是連在一起的,所以在set上找dfs序大于等于或小于等于該重鏈起始節點的點即可

代碼

#include<set> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define N 200021 using namespace std; int n, m, x, y, q, cc, ww, tot; int c[N], w[N], v[N], p[N], fa[N], sz[N], bv[N], hs[N]; int uj[N][20], dj[N][20], dep[N], top[N], head[N]; set<int>gm[N]; struct rec {int to, next; }a[N<<1]; int read() {char x=getchar();int d=1,l=0;while (x<'0'||x>'9') {if (x=='-') d=-1;x=getchar();}while (x>='0'&&x<='9') l=(l<<3)+(l<<1)+x-48,x=getchar();return l*d; } void add(int x, int y) {a[++tot].to = y;a[tot].next = head[x];head[x] = tot;return; } void dfs1(int x) {sz[x] = 1;for (int i = head[x]; i; i = a[i].next)if (a[i].to != fa[x]){fa[a[i].to] = x;dep[a[i].to] = dep[x] + 1;dfs1(a[i].to);sz[x] += sz[a[i].to];if (sz[a[i].to] > sz[hs[x]]) hs[x] = a[i].to;}return; } void dfs2(int x, int anc) {v[x] = ++ww;bv[ww] = x;top[x] = anc;if (top[p[w[x] + 1]] == top[x]) uj[x][0] = p[w[x] + 1];p[w[x]] = x; for (int i = 1; i <= cc; ++i)uj[x][i] = uj[uj[x][i - 1]][i - 1];//求ujif (hs[x]) dfs2(hs[x], anc);for (int i = head[x]; i; i = a[i].next)if (a[i].to != fa[x] && a[i].to != hs[x])dfs2(a[i].to, a[i].to);return; } void dfs3(int x) {for (int i = head[x]; i; i = a[i].next)if (a[i].to != fa[x] && a[i].to != hs[x])dfs3(a[i].to);if (hs[x]) dfs3(hs[x]);if (top[p[w[x] + 1]] == top[x]) dj[x][0] = p[w[x] + 1];//求djp[w[x]] = x;for (int i = 1; i <= cc; ++i)dj[x][i] = dj[dj[x][i - 1]][i - 1];return; } int lca(int x, int y) {while(top[x] != top[y]){if (dep[top[x]] < dep[top[y]]) swap(x, y);x = fa[top[x]];}if (dep[x] > dep[y]) swap(x, y);return x; } int fu(int x, int y, int now) {int g = bv[*--gm[now + 1].upper_bound(v[x])];//找一個小于等于該點的if (v[g] <= v[x] && w[g] == now + 1 && top[x] == top[g] && dep[g] >= dep[y] && g){now++;for (int i = cc; i >= 0; --i)if (top[x] == top[uj[g][i]] && dep[uj[g][i]] >= dep[y] && uj[g][i])g = uj[g][i], now += 1<<i;}if (dep[fa[top[x]]] >= dep[y] && top[x] != 1) return fu(fa[top[x]], y, now);else return now; } int fd(int x, int y, int now) {if (dep[fa[top[x]]] >= dep[y] && top[x] != 1) now = fd(fa[top[x]], y, now);//遞歸處理int gg = top[x], g;if (dep[gg] < dep[y]) gg = y;g = bv[*gm[now + 1].lower_bound(v[gg])];if (v[g] >= v[gg] && w[g] == now + 1 && top[x] == top[g] && dep[g] <= dep[x] && g){now++;for (int i = cc; i >= 0; --i)if (top[x] == top[dj[g][i]] && dep[dj[g][i]] <= dep[x] && dj[g][i])g = dj[g][i], now += 1<<i;}return now; } int main() {scanf("%d%d%d", &n, &cc, &m);cc = log2(cc);for (int i = 1; i <= m; ++i){scanf("%d", &x);c[x] = i;}for (int i = 1; i <= n; ++i){scanf("%d", &x);w[i] = c[x]; }for (int i = 1; i < n; ++i){scanf("%d%d", &x, &y);add(x, y);add(y, x);}dep[1] = fa[1] = 1;dfs1(1);dfs2(1, 1);for (int i = 1; i <= n; ++i)gm[w[i]].insert(v[i]);memset(p, 0, sizeof(p));dfs3(1);scanf("%d", &q);while(q--){scanf("%d%d", &x, &y);int z = lca(x, y), g;g = fu(x, z, 0);g = fd(y, z, g);printf("%d\n", g);}return 0; }

總結

以上是生活随笔為你收集整理的【树链剖分】【倍增】宝石(2021GDOI Day2 T1)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。