哩哩哩啦哩啦(lirililarila)
哩****啦
题目描述
给定一棵有 \(n\) 个点的树,根为 \(1\),设 \(dep_i\) 表示点 \(i\) 的深度。定义 \(S_{i,k}=\{x|lca(x,i)=i\wedge dep_x-dep_i=k\}\)(即点 \(i\) 的 \(k\) 级后代组成的点集)。再给出 \(m\) 个要求,第 \(i\) 个为 \((u_i,k_i)\)。你需要找到一对正整数 \(L,R\),使得它们满足以下条件:
- \(L\le R\);
- \(\forall i\in[1,m]\wedge i\in \mathbb N,S_{u_i,k_i}\cap[L,R]\neq\varnothing\);
- 在满足前两条的前提下,最小化 \(R-L\);
- 在满足前三条的前提下,最小化 \(L\)。
数据范围
\(1\le n,m\le2\times10^5\),\(1\le u_i,k_i\le n\)。
时空限制
\(2\text{s}\),\(512\text{Mb}\)。
做法
提供一个 \(O(n\log n)\) 的做法。
容易发现,如果一对要求 \((i,j)\) 满足 \(u_i\) 为 \(u_j\) 的祖先且 \(dep_{u_i}+k_i=dep_{u_j}+k_j\)(下文我们称之为“发生冲突”),那么要求 \(i\) 是没用的,因为此时一定有 \(S_{u_j,k_j}\subseteq S_{u_i,k_i}\),所以如果第 \(j\) 条要求被满足,那么第 \(i\) 条也一定会被满足,于是可以把要求 \(i\) 扔掉。这样一来,树上的每个点最多被一条留下来的要求覆盖。于是我们把问题转化成了两部分,第一部分是去掉无用的要求,第二部分是要在若干个大小总和不超过在 \(O(n)\) 级别的集合中从每个集合里选出一个数,使得选出的数极差最小且在极差最小的同时最小值最小。
先考虑第一部分。将所有要求按 \(dep_{u_i}\) 从大到小排序,这是因为如果两条要求发生了冲突,那么留下的一定是 \(u\) 更深的一个,所以先考虑 \(u\) 更深的要求。考虑第 \(i\) 条要求什么时候是没用的。显然如果 \(S_{u_i,k_i}\) 中的某些点已经被原来遍历过的要求覆盖过,那么第 \(i\) 条要求一定无用。由于 \(S_{u_i,k_i}\) 中的点一定深度相同且都为 \(dep_{u_i}+k_i\),所以我们可以将深度相同的点的 dfn 放到一个 vector 中,并给每一个深度建一棵树状数组(注意要用 vector 建,否则会爆空间)。于是我们就可以进行标记和查询了。
(为方便描述,下文将“有用的要求”简称为“要求”)。
再考虑第二部分。做扫描线。从大到小枚举 \(L\),求对于这个 \(L\) 符合条件的最小的 \(R\)。我们维护 \(wh_i\) 和 \(la_i\),分别表示第 \(i\) 个点被哪一个要求覆盖、\(S_{u_i,k_i}\cap [L,n]\) 中编号最小的点的编号(\(wh_i\) 在第一部分中求出)。由贪心可知,每条要求的集合中选 \(la\) 一定最优。用线段树维护哪些点被选、编号最大的被选的点的编号即可(线段树上被选权值为 \(1\),反之为 \(0\))。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,B=500;
vector<int> v[N];
int fa[N],dep[N];
int ll[N],rr[N],dfn[N],cnt,df[N];
vector<int> Nodes[N];
void dfs(int u){
ll[u]=rr[u]=dfn[u]=++cnt;
df[cnt]=u;
dep[u]=dep[fa[u]]+1;
Nodes[dep[u]].emplace_back(dfn[u]);
for(auto i:v[u]) dfs(i),rr[u]=rr[i];
}
int n,m;
struct fqr{
int id,u,k;
}q[N];
int mpos[N<<2],sum[N<<2];
int la[N],wh[N];
void change(int p,int l,int r,int x,int k){
if(!x) return;
if(l==r){
sum[p]+=k;
if(k==-1) mpos[p]=0;
else mpos[p]=l;
return;
}
int mid=l+r>>1;
if(x<=mid) change(p<<1,l,mid,x,k);
else change(p<<1|1,mid+1,r,x,k);
mpos[p]=max(mpos[p<<1],mpos[p<<1|1]);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
map<pair<int,int> ,int> mm;
vector<int> tr[N];
int cmp1(fqr f1,fqr f2){
return dep[f1.u]>dep[f2.u];
}
int lowbit(int x){
return x&-x;
}
void add(int p,int x,int k){
for(;x<=Nodes[p].size();x+=lowbit(x)) tr[p][x]+=k;
}
int ask(int p,int x){
int ans=0;
for(;x;x-=lowbit(x)) ans+=tr[p][x];
return ans;
}
int main(){
// freopen("lirililarila.in","r",stdin);
// freopen("lirililarila.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=2;i<=n;i++) cin>>fa[i],v[fa[i]].emplace_back(i);
dfs(1);
cin>>m;
for(int i=1;i<=m;i++) cin>>q[i].u>>q[i].k,q[i].id=i;
for(int i=1;i<=n;i++){
if(!Nodes[i].size()) break;
sort(Nodes[i].begin(),Nodes[i].end());
for(int j=1;j<=Nodes[i].size()+10;j++) tr[i].emplace_back(0);
}
sort(q+1,q+m+1,cmp1);
cnt=0;
for(int i=1;i<=m;i++){
if(mm.find({q[i].u,q[i].k})!=mm.end()) continue;
mm[{q[i].u,q[i].k}]=1;
int de=dep[q[i].u]+q[i].k;
if(!Nodes[de].size()) continue;
int l=lower_bound(Nodes[de].begin(),Nodes[de].end(),ll[q[i].u]+1)-Nodes[de].begin()+1,r=upper_bound(Nodes[de].begin(),Nodes[de].end(),rr[q[i].u])-Nodes[de].begin();
if(l>r) continue;
if(!(ask(de,r)-ask(de,l-1))){
cnt++;
for(int j=l-1;j<r;j++) wh[df[Nodes[de][j]]]=i,add(de,j+1,1);
}
}
int minl=1e9,ansr=0,ansl=0;
for(int i=n;i>0;i--){
if(wh[i]){
change(1,1,n,la[wh[i]],-1);
change(1,1,n,i,1);
la[wh[i]]=i;
}
if(sum[1]==cnt&&mpos[1]-i+1<=minl) ansl=i,ansr=mpos[1],minl=ansr-ansl+1;
}
cout<<ansl<<' '<<ansr;
}

浙公网安备 33010602011771号