zoukankan      html  css  js  c++  java
  • CF1062E Company

    CF1062E Company

    挺有意思的一道题。大结论题。

    结论:一堆点的 (LCA) 是它们中间 (dfs) 序最大的点和 (dfs) 序最小的点的 (LCA)

    搞个 (ST) 表维护区间内 (dfs) 序最大值和最小值,每次询问的时候尝试删去每个点,看看删完那个 (LCA) 深度更大就好了。

    至于删去之后的 (LCA) ,如果不怕烦,你可以维护区间 (dfs) 序的次大次小值,查询的时候取 区间最大值和次小值的 (LCA) ,次大值和最小值的 (LCA) 中深度较大的一个。

    不然可以像我一样维护区间的 (LCA) ,由于删去一个节点会导致区间分成 (2) 半,合并一下两个区间的 (LCA) 即可,但是多一个 (log) 能过就行

    关于结论怎么来的,多试几次就知道了,虽然会有罚时但是能AC就行,能看着样例想到结论的那是神仙。。。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef double db;
    #define fi first
    #define se second
    #define sz(v) (int)v.size()
    #define pb(x) push_back(x)
    #define mkp(x,y) make_pair(x,y)
    //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    //char buf[1<<21],*p1=buf,*p2=buf;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
    	while(isdigit(c))x=x*10+c-'0',c=getchar();
    	return f?x:-x;
    }
    #define N 100005
    int n,q,fa[N],mi[18][N],mx[18][N],lca[18][N],lg[N],pw2[30];
    int siz[N],son[N],dep[N],top[N],dfn[N],tmr;
    struct edge{int nxt,to;}e[N];
    int head[N],num_edge;
    void addedge(int fr,int to){
    	++num_edge;
    	e[num_edge].nxt=head[fr];
    	e[num_edge].to=to;
    	head[fr]=num_edge;
    }
    void dfs1(int u,int ft){
    	siz[u]=1;
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		dep[v]=dep[u]+1,dfs1(v,u),siz[u]+=siz[v];
    		if(siz[v]>siz[son[u]])son[u]=v;
    	}
    }
    void dfs2(int u,int tp){
    	top[u]=tp,dfn[u]=++tmr;
    	if(son[u])dfs2(son[u],tp);
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    int LCA(int x,int y){
    	if(!x||!y)return x|y;
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]])x^=y^=x^=y;
    		x=fa[top[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    int ask_min(int l,int r){
    	int x=lg[r-l+1],t=r-pw2[x]+1;
    	return dfn[mi[x][l]]<dfn[mi[x][t]]?mi[x][l]:mi[x][t];
    }
    int ask_max(int l,int r){
    	int x=lg[r-l+1],t=r-pw2[x]+1;
    	return dfn[mx[x][l]]<dfn[mx[x][t]]?mx[x][t]:mx[x][l];
    }
    int ask_LCA(int l,int r){
    	if(l>r)return 0;
    	int x=lg[r-l+1],t=r-pw2[x]+1;
    	return LCA(lca[x][l],lca[x][t]);
    }
    signed main(){
    	n=read(),q=read();
    	for(int i=2;i<=n;++i)addedge(fa[i]=read(),i);
    	dfs1(1,0),dfs2(1,1);
    	pw2[0]=1;for(int i=1;i<=20;++i)pw2[i]=pw2[i-1]<<1;
    	lg[0]=-1;for(int i=1;i<=n;++i)lg[i]=lg[i>>1]+1;
    	for(int i=1;i<=n;++i)mx[0][i]=mi[0][i]=lca[0][i]=i;
    	for(int i=1;i<=lg[n];++i)
    		for(int j=1;j+pw2[i]-1<=n;++j){
    			int t=j+pw2[i-1];
    			if(dfn[mx[i-1][j]]<dfn[mx[i-1][t]])mx[i][j]=mx[i-1][t];
    			else mx[i][j]=mx[i-1][j];
    			if(dfn[mi[i-1][j]]<dfn[mi[i-1][t]])mi[i][j]=mi[i-1][j];
    			else mi[i][j]=mi[i-1][t];
    			lca[i][j]=LCA(lca[i-1][j],lca[i-1][t]);
    		}
    	while(q--){
    		int l=read(),r=read(),p=lg[r-l+1],t=r-pw2[p]+1;
    		int idx=ask_min(l,r),idy=ask_max(l,r);
    		int x=LCA(ask_LCA(l,idx-1),ask_LCA(idx+1,r)),y=LCA(ask_LCA(l,idy-1),ask_LCA(idy+1,r));
    		dep[x]>dep[y]?printf("%d %d
    ",idx,dep[x]):printf("%d %d
    ",idy,dep[y]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [Effective JavaScript 笔记]第54条:将undefined看做“没有值”
    [Effective JavaScript 笔记]第53条:保持一致的约定
    UDP打洞原理介绍
    Uboot启动分析之Start.S
    MMU
    linux_shell
    SSH2配置
    线程同步
    C#线程基础
    客户端服务器通讯常用的一种方法——Marshal类
  • 原文地址:https://www.cnblogs.com/zzctommy/p/13920190.html
Copyright © 2011-2022 走看看