线段树合并与分裂
Posted 清澈不在远方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树合并与分裂相关的知识,希望对你有一定的参考价值。
线段树合并
BZOJ4552
有一个n的排列,进行m次操作,每次操作是将一个区间升序或降序排序。
请你输出m次操作后第p个位置的值。
BZOJ4756
题意
给一棵树,每个节点都有一个值,求其子树中值比他大的个数
分析
线段树合并
先将点离散化,动态开线段树,依靠dfs序回溯的时候实现查询子树和合并线段树的操作即可
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn = 1e5 + 10; int a[maxn], b[maxn]; int lson[maxn], rson[maxn]; int tree[maxn]; int root[maxn]; int cnt = 0; int n; int ans[maxn]; vector<int>G[maxn]; int temp; int newnode() { ++cnt; lson[cnt]=rson[cnt]=0; return cnt; } void push_up(int x) { tree[x]=tree[lson[x]]+tree[rson[x]]; } int build(int x, int l ,int r,int num) { if(!x) x=newnode(); if(l==r) { tree[x]=1; return x; } int mid = (l+r)/2; if(num<=mid) lson[x] = build(lson[x], l, mid, num); else rson[x] = build(rson[x], mid+1, r, num); push_up(x); return x; } int query(int x, int l, int r, int ql, int qr) { if(ql<=l && qr>=r) return tree[x]; int mid = (l+r)/2; int ans = 0; if(ql<=mid && lson[x]) ans+=query(lson[x], l, mid, ql, qr); if(qr>mid && rson[x]) ans+=query(rson[x], mid+1,r, ql,qr); return ans; } int mercy(int root1, int root2) { if(!root1) return root2; if(!root2) return root1; lson[root1] = mercy(lson[root1], lson[root2]); rson[root1] = mercy(rson[root1], rson[root2]); tree[root1] += tree[root2]; return root1; } void dfs(int now, int fa) { int len = G[now].size(); for(int i = 0; i < len; i++) { int k = G[now][i]; if(k == fa) continue; dfs(k, now); ans[now]+=query(root[k],1,temp,min(a[now]+1,temp),temp); mercy(root[now], root[k]); } } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); b[i]=a[i]; } sort(b+1, b+n+1); temp = unique(b+1, b+n+1)-b-1; for(int i = 1; i <=n; i++) { a[i] = lower_bound(b+1, b+temp+1,a[i])-b; } int x; for(int i = 2; i <= n;i++) { scanf("%d", &x); G[i].push_back(x); G[x].push_back(i); } for(int i = 1; i <= n; i++) { root[i] = build(root[i], 1 , temp, a[i]); } dfs(1, 1); for(int i = 1; i <= n; i++) printf("%d ", ans[i]); return 0; }
以上是关于线段树合并与分裂的主要内容,如果未能解决你的问题,请参考以下文章