zoukankan      html  css  js  c++  java
  • BZOJ4307: Maishroom & Class

    感觉有一点题面没有说得特别明确,就是一个人代替了其他人之后,另一个可以被他代替的人就不能让他来代替自己了。

    每个人向自己可以代替的人连边,额外增加一个源点$r$向所有助教连边。第一问答案是$r$不能到达的点的个数。对于第二问,求出支配树,每个以$r$为父亲的点的子树中任选两个点都满足条件。

    #include<cstdio>
    struct edge{
    	int v;
    	edge*s;
    };
    template<int N,int M>
    struct graph{
    	edge*l,e[M],*h[N];
    	graph():l(e){}
    	void ins(int u,int v){
    		*l={v,h[u]};
    		h[u]=l++;
    	}
    };
    const int N=5005;
    const int M=25005;
    graph<N,M>t1,t2;
    graph<N,N>buc;
    int n,f[N],par[N],semi[N],ver[N],dom[N],anc[N],lab[N];
    void dfs(int u){
    	semi[u]=++n;
    	ver[n]=u;
    	for(edge*i=t1.h[u];i;i=i->s)
    		if(!semi[i->v]){
    			par[i->v]=u;
    			dfs(i->v);
    		}
    }
    inline int eval(int u){
    	if(anc[anc[u]]){
    		eval(anc[u]);
    		if(semi[lab[anc[u]]]<semi[lab[u]])
    			lab[u]=lab[anc[u]];
    		anc[u]=anc[anc[u]];
    	}
    	return lab[u];
    }
    void sol(int r){
    	dfs(r);
    	for(int i=1;i<=n;++i)
    		lab[ver[i]]=ver[i];
    	for(int i=n;i>=2;--i){
    		int u=ver[i];
    		for(edge*i=t2.h[u];i;i=i->s)
    			if(semi[i->v]){
    				int w=eval(i->v);
    				if(semi[w]<semi[u])
    					semi[u]=semi[w];
    			}
    		buc.ins(ver[semi[u]],u);
    		anc[u]=par[u];
    		for(edge*i=buc.h[par[u]];i;i=i->s){
    			int w=eval(i->v);
    			dom[i->v]=semi[w]<semi[i->v]?w:par[u];
    		}
    		buc.h[par[u]]=0;
    	}
    	for(int i=2;i<=n;++i){
    		int u=ver[i];
    		if(dom[u]!=ver[semi[u]])
    			dom[u]=dom[dom[u]];
    	}
    }
    void ins(int u,int v){
    	t1.ins(u,v);
    	t2.ins(v,u);
    }
    int main(){
    	struct{
    		operator int(){
    			int x=0,c=getchar();
    			while(c<48)
    				c=getchar();
    			while(c>47)
    				x=x*10+c-48,c=getchar();
    			return x;
    		}
    	}buf;
    	int r=buf+1,l=buf;
    	for(int u=1;u<=l;++u){
    		int a=buf;
    		while(a--)
    			ins(buf,u);
    	}
    	for(int u=l+1;u<r;++u)
    		ins(r,u);
    	sol(r);
    	int s=0;
    	for(int i=n;i>=2;--i){
    		int&a=f[ver[i]];
    		int v=dom[ver[i]];
    		f[v]+=++a;
    		if(v==r)
    			s+=a*(a-1)/2;
    	}
    	printf("%d %d
    ",r-n,s);
    }
    
  • 相关阅读:
    二叉树学习随笔
    结构体初始化中的数组赋值
    C和FORTRAN的快速傅里叶/余弦/正弦变换(Fast Fourier/Cosine/Sine Transform)开源库分享
    Java简单的数组用法尝试,和C语言很不一样
    中位数( 优先队列较优处理 )
    单调队列 数组写法qwq
    P1886 滑动窗口
    Sicily 2014. Dairy Queen
    P3385 【模板】负环
    [USACO06DEC]虫洞Wormholes (负环模板)
  • 原文地址:https://www.cnblogs.com/f321dd/p/9390156.html
Copyright © 2011-2022 走看看