zoukankan      html  css  js  c++  java
  • 主仆见证了 Hobo 的离别 题解

    前言:

    题面挺神仙。反正我考试的时候看了40分钟也没看懂。
    后来改题感觉自己写的挺假,没想到加个(k==1)的特判竟然就A了?无语力。

    解析:

    看懂题以后就好说了。首先这显然是一个树形结构。我们考虑把“交”的操作放到一棵树上,把“并”的操作放到一棵树上。
    考虑建边。比如将((1,2,3))并成((4)),那么就在并树上,将(1,2,3)的父亲设置成(4)
    然后,对于每个询问((x,y)),如果在交树上,(x)(y)的祖先,或在并树上,(y)(x)的祖先,那么答案就是(1),否则是(0)
    看起来有手就行。不过细节还是要注意。

    关于实现上的细节:

    1.

    我们在建立模型的时候,显然建的是有向边,由儿子指向父亲。但我们在真正建树的时候,是要建无向边。因为无向边比较好维护。那此时怎么判断父子关系呢?
    首先,有一个性质。每个节点的父亲的编号一定比自己的编号大。也就是说,大的点一定在上面。因为维护的是一片森林,所以可以根据这个性质找到每棵树的根节点。
    所以可以考虑按编号从大到小DFS一遍。按照DFS序判断父子关系。
    写过树剖的人都知道,一颗子树内的dfs序是连续的。因此假如y是x的父亲,那么(dfn[y]<=dfn[x]<=dfn[x]+size[x]-1<=dfn[y]+size[y]-1)

    2.

    注意一个细节。(k==1)的时候,交和并等价。那么既要在交树上建边,又要在并树上建边。
    然后就可以A掉这道题了。

    关于正确性:

    1.为什么只需要判断x和y的关系,不需要判断y的祖先和x的关系呢?

    首先,对于在y到根节点上的路径上的点(不包括根节点),那么这些节点既有入度,也有出度,那么这些点就不可能在另外一棵树上出现了。
    其次,对于根节点,它只可能去合成别的节点,那么它在另一棵树上一定没有入度。也就是说,即使根节点在另一棵树上出现,它也必然是叶子节点,不可能是x的父亲,所以不用判。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=500000+10;
    int n,m,cntj,cntb,totot,totj,totb,Time;
    struct node{
    	int to,next;
    }edgej[maxn],edgeb[maxn];
    int headj[maxn],headb[maxn],dfnb[maxn],dfnj[maxn],sizeb[maxn],sizej[maxn];
    struct que{
    	int x,y;
    }b[maxn];
    bool vis[maxn];
    void addj(int from,int to){
    	edgej[++cntj].to=to;
    	edgej[cntj].next=headj[from];
    	headj[from]=cntj;
    }
    void addb(int from,int to){
    	edgeb[++cntb].to=to;
    	edgeb[cntb].next=headb[from];
    	headb[from]=cntb;
    }
    void dfs1(int u,int f){
    	dfnj[u]=++Time;
    	sizej[u]=1;
    	vis[u]=1;
    	for(int i=headj[u];i;i=edgej[i].next){
    		int v=edgej[i].to;
    		if(v==f) continue;
    		dfs1(v,u);
    		sizej[u]+=sizej[v];
    	}
    }
    void dfs2(int u,int f){
    	dfnb[u]=++Time;
    	sizeb[u]=1;
    	vis[u]=1;
    	for(int i=headb[u];i;i=edgeb[i].next){
    		int v=edgeb[i].to;
    		if(v==f) continue;
    		dfs2(v,u);
    		sizeb[u]+=sizeb[v];
    	}
    }
    int get_ans(int x,int y){
    	if(dfnj[x]<=dfnj[y]&&dfnj[x]+sizej[x]>=dfnj[y]+sizej[y]) return 1;
    	if(dfnb[y]<=dfnb[x]&&dfnb[y]+sizeb[y]>=dfnb[x]+sizeb[x]) return 1;
    	return 0;
    }
    void Solve(){
    	scanf("%d%d",&n,&m);
    	for(int i=1,op,k,ss;i<=m;++i){
    		scanf("%d",&ss);
    		if(ss){
    			totot++;
    			scanf("%d%d",&b[totot].x,&b[totot].y);
    		}else{
    			scanf("%d%d",&op,&k);
    			if(op){
    				totb++;
    				if(k>1){
    					for(int j=1;j<=k;++j){
    						scanf("%d",&ss);
    						addb(ss,totb+totj+n);
    						addb(totb+totj+n,ss);
    					}
    				}else{
    					for(int j=1;j<=k;++j){
    						scanf("%d",&ss);
    						addb(ss,totb+totj+n);
    						addb(totb+totj+n,ss);
    						addj(ss,totb+totj+n);
    						addj(totb+totj+n,ss);
    					}
    				}
    			}else{
    				totj++;
    				if(k>1){
    					for(int j=1;j<=k;++j){
    						scanf("%d",&ss);
    						addj(ss,totj+totb+n);
    						addj(totj+totb+n,ss);
    					}
    				}else{
    					for(int j=1;j<=k;++j){
    						scanf("%d",&ss);
    						addb(ss,totb+totj+n);
    						addb(totb+totj+n,ss);
    						addj(ss,totb+totj+n);
    						addj(totb+totj+n,ss);
    					}
    				}
    			}
    		}
    	}
    	//printf("n==%d totj=%d totb=%d cntj==%d cntb==%d
    ",n,totj,totb,cntj,cntb);
    	for(int i=totj+totb+n;i;--i) if(!vis[i]) dfs1(i,0);
    	memset(vis,0,sizeof(vis));
    	Time=0;
    	for(int i=totb+totj+n;i;--i) if(!vis[i]) dfs2(i,0); 
    	//for(int i=1;i<=totj+totb+n;++i) printf("dfnj[%d]=%d dfnb[%d]=%d sizej[%d]=%d sizeb[%d]=%d
    ",i,dfnj[i],i,dfnb[i],i,sizej[i],i,sizeb[i]);
    	for(int i=1;i<=totot;++i) printf("%d
    ",get_ans(b[i].x,b[i].y));
    }
    int main(){
    	freopen("friendship.in","r",stdin);
    	freopen("friendship.out","w",stdout);
    	Solve();
    	return 0;
    }
    
    
  • 相关阅读:
    两个51相互之间单片机如何进行串口通信
    (stm32f103学习总结)—stm32pwm
    (stm32f103学习总结)—stm32 PMW输出实验
    cpu指令如何读写硬盘
    线程进程同步
    stm32+lwip
    opc
    open62541-server编程
    linux 下time函数
    close与shutdown
  • 原文地址:https://www.cnblogs.com/wwcdcpyscc/p/13830049.html
Copyright © 2011-2022 走看看