CF1062E Company

CF1062E Company

链接

cf
luogu

题目大意

给定一颗树,有若干个询问,每个询问给出 l,r,要求编号为 ll~rr 的点任意删去一个之后剩余点的 LCA 深度最大,输出删去点的编号和 LCA 的最大深度

思路

一堆点的lca就是dfs序列的最大和最小的lca
因为只能删除一个点,那就看看删除最大的优秀还是删除最小的优秀。
修改其他的lca是不变的。查询次大线段树麻烦,主席树还能短一点。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int read() {
	int x=0,f=1;char s=getchar();
	for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
	for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
	return x*f;
}
int n,q,a[N];
vector<int> G[N];
namespace seg {
	struct node {
		int ls,rs,siz,nb;
	}e[N*30];
	int cnt,rt[N];
	void insert(int &rt,int old,int l,int r,int id,int nb) {
		rt=++cnt;
		e[rt]=e[old];
		e[rt].siz++;
		if(l==r) return e[rt].nb=nb,void();
		int mid=(l+r)>>1;
		if(id<=mid) insert(e[rt].ls,e[old].ls,l,mid,id,nb);
		else insert(e[rt].rs,e[old].rs,mid+1,r,id,nb);		
	}
	int k_th(int rt,int old,int l,int r,int k) {
		if(l==r) return e[rt].nb;
		int now=e[e[rt].ls].siz-e[e[old].ls].siz;
		int mid=(l+r)>>1;
		if(now>=k) return k_th(e[rt].ls,e[old].ls,l,mid,k);
		else return k_th(e[rt].rs,e[old].rs,mid+1,r,k-now);
	}
}
namespace diss_tree {
	int dep[N],siz[N],fa[N];
	int top[N],son[N],cnt;
	void dfs1(int u,int f) {
        a[u]=++cnt;
		fa[u]=f;
		siz[u]=1;
		for(auto v:G[u]) {
			if(f==v) continue;
            dep[v]=dep[u]+1;
			dfs1(v,u);
			siz[u]+=siz[v];
			if(siz[son[u]]<siz[v]) son[u]=v;
		}
	}
	void dfs2(int u,int topf) {
		top[u]=topf;
		if(!son[u]) return;
		dfs2(son[u],topf);
		for(auto v:G[u])
			if(!top[v]) dfs2(v,v);
	}
	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]];
		}
		return dep[x]<dep[y] ? x : y;
	}
}
int main() {
	n=read(),q=read();
	for(int i=2;i<=n;++i) {
		int x=read();
		G[x].push_back(i);
		G[i].push_back(x);
	}
	diss_tree::dfs1(1,0);
	diss_tree::dfs2(1,1);
	for(int i=1;i<=n;++i) seg::insert(seg::rt[i],seg::rt[i-1],1,n,a[i],i);
	for(int i=1;i<=q;++i) {
		int x=read(),y=read();
		int first_max=seg::k_th(seg::rt[y],seg::rt[x-1],1,n,1);
		int second_max=seg::k_th(seg::rt[y],seg::rt[x-1],1,n,2);
		int first_min=seg::k_th(seg::rt[y],seg::rt[x-1],1,n,y-x+1);
		int second_min=seg::k_th(seg::rt[y],seg::rt[x-1],1,n,y-x);
		int tmp_x=diss_tree::dep[diss_tree::lca(first_max,second_min)];
		int tmp_y=diss_tree::dep[diss_tree::lca(second_max,first_min)];
		if(tmp_x > tmp_y) printf("%d %d
",first_min,tmp_x);
		else printf("%d %d
",first_max,tmp_y);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/dsrdsr/p/10785822.html