zoukankan      html  css  js  c++  java
  • CF1328E Tree Queries

    CF1328E Tree Queries
    应该还是比较妙的

    题意

    给你一个树,然后多次询问
    每次询问给出一堆节点,问你是否能找到一个从根出发的链,是的对于给出的每个节点,都能找出链上的点,是的他们的距离小于等于(1)
    (nleq 2cdot 10^5,mleq 2cdot 10^5,sum kleq 2cdot 10^5)
    其中(m)是询问次数,(k)是每次给出的点数


    首先,一个点要想符合题目的条件,无非有两种情况
    一种是就在链上,这个好说
    另一种是距离链上的点距离为(1),那么,肯定是他的父亲在链上

    所以,我们可以把每个给出的点转换成他的父亲,问题就变成看:能否找到一个链,是的这些点都在链上
    这样的转换对第一种肯定是没有影响的,一个点在链上,他的父亲肯定也在链上

    所以考虑转换后的问题
    我首先想到的是,找出深度最大的节点,对于其它每个点和它求 LCA ,如果这个 LCA 不是那个深度较小的点,说明肯定连不成一个链
    这一点判断基于那个链必须从根出发
    然后写完代码交上去:


    #100 WA!
    emmm,估计是写炸了,第一个MLE是邻接表忘开2倍了

    然而并没看出错,所以考虑一种实现更简单的方法
    上面求 LCA 其实可以理解为从下向上考虑,那么还有一种从上往下考虑的方法:
    先把每个点按深度从小到大排序,然后如果p[i+1]不在p[i]的子树里,那么肯定连不成一个链
    至于怎么判断也很简单,记录一个dfs序和每个节点子树大小就行,具体见代码的check函数

    ( exttt{code.})

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	int x=0,y=1;
    	char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    int n,m;
    int fir[200006],nex[400006],to[400006],tot;
    int p[200006],fa[200006],size[200006];
    int dfn[200006],deep[200006],dfscnt;
    inline void add(int a,int b){
    	to[++tot]=b;
    	nex[tot]=fir[a];fir[a]=tot;
    }
    void dfs(int u,int fat){
    	fa[u]=fat;deep[u]=deep[fat]+1;dfn[u]=++dfscnt;size[u]=1;
    	for(reg int i=fir[u];i;i=nex[i])if(to[i]!=fat) dfs(to[i],u),size[u]+=size[to[i]];
    }
    inline int check(int a,int b){//看b是不是在a的子树 
    	if(dfn[b]<dfn[a]) return 0;
    	if(dfn[b]>=dfn[a]+size[a]) return 0;
    	//这里一定是>=,如果dfn[b]=dfn[a]+size[a],也说明b并不在a的子树里,因为统计size[a]的时候a这个点也被算进去了 
    	return 1;
    }
    inline int cmp(int x,int y){return deep[x]<deep[y];}
    int main(){
    	n=read();m=read();
    	for(reg int a,b,i=1;i<n;i++){
    		a=read();b=read();
    		add(a,b);add(b,a);
    	}
    	reg int k;
    	dfs(1,1);
    	while(m--){
    		k=read();
    		for(reg int i=1;i<=k;i++) p[i]=fa[read()];
    		std::sort(p+1,p+1+k,cmp);
    		for(reg int i=2;i<=k;i++)
    			if(!check(p[i-1],p[i])) goto NO;
    		std::puts("YES");continue;
    		NO:;std::puts("NO");
    	}
    	return 0;
    }
    

    那个没A的LCA做法也放在这,也许哪天很闲的时候会再调调
    记录

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	int x=0,y=1;
    	char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    int n,m;
    int fir[200006],nex[400006],to[400006],tot;
    int p[200006];
    int fa[23][200006],deep[200006];
    inline void add(int a,int b){
    	to[++tot]=b;
    	nex[tot]=fir[a];fir[a]=tot;
    }
    void dfs(int u,int fat){
    	fa[0][u]=fat;deep[u]=deep[fat]+1;
    	for(reg int i=fir[u];i;i=nex[i])if(to[i]!=fat) dfs(to[i],u);
    }
    inline int check(int a,int b){
    	for(reg int i=20;~i;i--)
    		if(deep[fa[i][b]]>=deep[a]) b=fa[i][b];
    	return a==b;
    }
    int main(){
    	n=read();m=read();
    	for(reg int a,b,i=1;i<n;i++){
    		a=read();b=read();
    		add(a,b);add(b,a);
    	}
    	reg int k,maxdeep,maxdeepid;
    	dfs(1,1);
    	for(reg int i=1;i<=n;i++)
    		for(reg int j=1;j<=20;j++) fa[j][i]=fa[j-1][fa[j-1][i]];
    	while(m--){
    		k=read();maxdeep=0;
    		for(reg int i=1;i<=k;i++){
    			p[i]=fa[0][read()];
    			if(deep[p[i]]>maxdeep) maxdeep=deep[p[i]],maxdeepid=p[i];
    		}
    		for(reg int i=1;i<=k;i++)if(p[i]!=maxdeepid){
    			if(!check(p[i],maxdeepid)) goto NO;
    		}
    		std::puts("YES");continue;
    		NO:;std::puts("NO");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Hadoop的多节点集群详细启动步骤(3或5节点)
    Hive的单节点集群详细启动步骤
    HDU-1039-Easier Done Than Said?(Java &amp;&amp; 没用正則表達式是我的遗憾.....)
    Linux下套接字具体解释(三)----几种套接字I/O模型
    C++晋升之std中vector的实现原理(标准模板动态库中矢量的实现原理)
    POJ 1781 In Danger Joseph环 位运算解法
    sublime搜索和替换--正则
    quarze的工作原理
    CF437D(The Child and Zoo)最小生成树
    HDU2504 又见GCD
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12585217.html
Copyright © 2011-2022 走看看