2021牛客暑期多校训练营9E Eyjafjalla (倍增,dfs序,主席树)
Posted 小哈里
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营9E Eyjafjalla (倍增,dfs序,主席树)相关的知识,希望对你有一定的参考价值。
E Eyjafjalla
题意:
- 题意:给定一个以1为根的有根树,孩子的点权小于父亲的点权。 多次询问,每次询问包含x节点的权值范围为[l, r] 的极大连通块的大小。
思路:
- 病毒传播可以看作两个阶段,第一个阶段先上升到最高的一个节点p(p的温度大于r),第二阶段感染p的子树中所有温度大于l的城市。
- 第一阶段可以通过倍增法求得p
- 第二阶段相当于在p的子树中查询权值大于l的节点个数,根据每个节点的dfs序建立可持久化线段树, 然后在线段树上查询即可。时间复杂度O(n log n)。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n;
vector<int>G[maxn];
int a[maxn];
//倍增找p
int fa[maxn], up[maxn][30];
void getf(){
for(int i = 1; i <= n; i++)up[i][0]=fa[i];
for(int j = 1; j <= 20; j++)
for(int i = 1; i <= n; i++)
up[i][j] = up[up[i][j-1]][j-1];//i向上2^j层的祖先
}
//预处理dfs序[dfn,low]
int clk, dfn[maxn], low[maxn], ord[maxn];
void pre(int x, int f){
fa[x] = f;
dfn[x] = ++clk;
ord[clk] = x;
for(int to: G[x]){
if(to != f)pre(to,x);
}
low[x] = clk;
}
//主席树
int tot, rt[maxn<<5], lch[maxn<<5], rch[maxn<<5], sum[maxn<<5];
void modify(int x, int f, int l, int r, int pos){ //v[pos]+=1;
if(l==r){
sum[x] = sum[f]+1;
return ;
}
int mid = l+r>>1;
if(pos <= mid){
rch[x] = rch[f];//直接用上一棵树的节点
lch[x] = ++tot; //需要新建节点
modify(lch[x], lch[f], l, mid, pos);
}else{
lch[x] = lch[f];
rch[x] = ++tot;
modify(rch[x], rch[f], mid+1,r,pos);
}
sum[x] = sum[lch[x]]+sum[rch[x]];
}
int query(int p, int l, int r, int ll, int rr){//查询版本线段树值域范围在[l,r]的节点个数
if(p==0)return 0;
if(ll<=l && r<=rr)return sum[p];
if(l>rr || r<ll)return 0;
int mid = (l+r)>>1, ans = 0;
ans += query(lch[p], l, mid, ll, rr);
ans += query(rch[p], mid+1, r, ll, rr);
return ans;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i = 1; i < n; i++){
int u, v; cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
for(int i = 1; i <= n; i++)cin>>a[i]; a[0] = 1e9+7;
pre(1,0);
getf();
for(int i = 1; i <= n; i++){//建立n个版本的值域线段树
rt[i] = ++tot;
modify(rt[i], rt[i-1], 1, 1e9, a[ord[i]]);
}
int q; cin>>q;
while(q--){
int x, l, r; cin>>x>>l>>r;
if(a[x]<l || a[x]>r){ cout<<"0\\n"; continue; }
for(int i = 20; i >= 0; i--){//先上升到最高点,满足刚好a[x]>r
if(a[up[x][i]]<=r)x=up[x][i];
}
//查询子树[dfn[x]-1, low[x]]中,权值在[l,r]中的节点个数
cout<<query(rt[low[x]], 1, 1e9, l,r)-query(rt[dfn[x]-1], 1,1e9, l, r)<<"\\n";
}
return 0;
}
以上是关于2021牛客暑期多校训练营9E Eyjafjalla (倍增,dfs序,主席树)的主要内容,如果未能解决你的问题,请参考以下文章