Gym - 101848C树链剖分 + 线段树 + 动态开点

    xiaoxiao2023-11-20  179

    学习自 : 大佬博客

    题意: 给一棵树,每一个节点上有多个权值,q次询问,求对于某一个节点,从其自身到根节点的路径上第一个含有给定权值的点的编号;

    思路:对每一个权值建立一颗线段树,然后用线段树维护区间最大值即可求解.

    #include <iostream> using namespace std; const int N = 1e5 + 10, MAXN = 3e7 + 10; struct edge { int to, next; }Edge[N<<1]; int cnt, head[N]; int num[N], top[N], f[N], son[N], dep[N], id[N]; int lc[MAXN], rc[MAXN], R[MAXN], MAX[MAXN]; //用R[]来储存每一个线段树的根节点,通过lc[]与rc[]使线段树互相独立; inline int max(int a,int b){ return a > b ? a : b; } inline void add_edge(int from,int to) { Edge[++cnt].to = to; Edge[cnt].next = head[from]; head[from] = cnt; } inline void dfs1(int v) { num[v] = 1; dep[v] = dep[f[v]] + 1; for(int i = head[v]; i; i = Edge[i].next){ int to = Edge[i].to; f[to] = v; dfs1(to); num[v] += num[to]; if(num[to] > num[son[v]]) son[v] = to; } } inline void dfs2(int v,int tp) { top[v] = tp; id[v] = ++cnt; if(!son[v]) return ; dfs2(son[v], tp); for(int i = head[v]; i; i = Edge[i].next){ int to = Edge[i].to; if(to == son[v]) continue; dfs2(to,to); } } inline void update(int L,int C,int l,int r,int &rt) { if(!rt){ rt = ++cnt; MAX[rt] = C; } MAX[rt] = max(MAX[rt], C); if(l == r) return ; int m = (l+r)>>1; if(L <= m) update(L,C,l,m,lc[rt]); else update(L,C,m+1,r,rc[rt]); } inline int query(int L,int R,int l,int r,int rt) { if(!rt) return 0; if(L <= l && r <= R) return MAX[rt]; int m = (l+r)>>1, ans = 0; if(L <= m) ans = max(ans, query(L,R,l,m,lc[rt])); if(m < R) ans = max(ans, query(L,R,m+1,r,rc[rt])); return ans; } inline int querys(int A,int x) { int ans = 0; while(top[A] != top[1]){ ans = max(ans, query(id[top[A]],id[A],1,1e6,R[x])); A = f[top[A]]; } return max(ans, query(id[1],id[A],1,1e6,R[x])); } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int n, m, q, A, B; cin>>n; for(int i = 2; i <= n; ++i){ cin>>A; add_edge(A,i); } cnt = 0; dfs1(1); dfs2(1,1); cnt = 0; for(int i = 1; i <= n; ++i){ cin>>m; for(int j = 0; j < m; ++j){ cin>>A; update(id[i],i,1,1e6,R[A]); }//因为题目保证了(1 <= pi <= i - 1) 因此此处可直接用类的编号来更新,否则需要用类新的编号来更新; } cin>>q; for(int i = 0; i < q; ++i){ cin>>A>>B; int ans = querys(A,B); if(ans == 0) cout<<-1<<'\n'; else cout<<ans<<'\n'; } return 0; }

    呜呜呜,从知道这篇博客到会写这份代码过了一个多月的时间(爽)

     

     

     

    最新回复(0)