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;
    }
    
  • 相关阅读:
    Ubuntu 14.04的SWAP 为0
    堆和栈的区别(转过无数次的文章)
    加法乘法判断溢出(转)
    大端格式、小端格式(转)
    Linux 目录操作和4中文件拷贝效率测试
    Linux使用标准IO的调用函数,分3种形式实现
    支持 onload 事件的元素
    $().each() 和 $.each()
    npm install --save 与 npm install --save-dev 的区别
    <!DOCTYPE html>作用
  • 原文地址:https://www.cnblogs.com/zzctommy/p/13920190.html
Copyright © 2011-2022 走看看