• [CC-ADJLEAF2]Adjacent Leaves


    [CC-ADJLEAF2]Adjacent Leaves

    题目大意:

    给定一棵有根树,考虑从根开始进行DFS,将所有叶子按照被遍历到的顺序排列得到一个序列。

    定义一个叶子集合合法,当且仅当存在一种DFS的方式使得这个叶子集合在序列中的出现位置是一个连续子串。
    给出一个(n(nle5 imes10^5))个点的无根树,(m(mle5 imes10^5))次询问,求以(R)为根的情况下叶子集合(S(sum|S|le5 imes10^5))是否合法。

    思路:

    定义(leaf[x])为以(x)为根的子树内叶子结点的个数,(cnt[x])为以(x)为根的子树内属于(S)的点的个数。

    定义以(x)为根的子树是“不满的”,当且仅当(cnt[x] e0)(cnt[x] e leaf[x])

    对于一个结点(x),若其有(ge3)个子树是不满的,或其有(2)个子树不满,且(cnt[x] e|S|),则(S)不合法。

    对于每次询问,用一次(mathcal O(n))的树形DP求解,我们就得到了一个(mathcal O(nm))的做法。

    由于(sum|S|le5 imes10^5),我们可以建立虚树,将每次DFS的点数缩小为(|S|),此时一次DP的时间复杂度为(mathcal O(|S|log n)),总时间复杂度(mathcal O(sum|S|log n))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=5e5+1,logN=19;
    std::vector<int> e[N],node;
    inline void add_edge(const int &u,const int &v) {
    	e[u].push_back(v);
    	e[v].push_back(u);
    }
    int r,dep[N],anc[N][logN],dfn[N],s[N],leaf[N],tot;
    inline int lg2(const float &x) {
    	return ((unsigned&)x>>23&255)-127;
    }
    void dfs(const int &x,const int &par) {
    	anc[x][0]=par;
    	dfn[x]=++tot;
    	dep[x]=dep[par]+1;
    	leaf[x]=e[x].size()==1;
    	for(register int i=1;i<=lg2(dep[x]);i++) {
    		anc[x][i]=anc[anc[x][i-1]][i-1];
    	}
    	for(auto &y:e[x]) {
    		if(y==par) continue;
    		dfs(y,x);
    		leaf[x]+=leaf[y];
    	}
    }
    inline int lca(int x,int y) {
    	if(dep[x]<dep[y]) std::swap(x,y);
    	for(register int i=lg2(dep[x]-dep[y]);i>=0;i--) {
    		if(dep[anc[x][i]]>=dep[y]) {
    			x=anc[x][i];
    		}
    	}
    	for(register int i=lg2(dep[x]);i>=0;i--) {
    		if(anc[x][i]!=anc[y][i]) {
    			x=anc[x][i];
    			y=anc[y][i];
    		}
    	}
    	return x==y?x:anc[x][0];
    }
    inline bool is_anc(const int &x,int y) {
    	//x shi y de zuxian
    	if(dep[x]>dep[y]) return false;
    	for(register int i=lg2(dep[y]-dep[x]);i>=0;i--) {
    		if(dep[anc[y][i]]>=dep[x]) {
    			y=anc[y][i];
    		}
    	}
    	return x==y;
    }
    inline int jump(int x,const int &d) {
    	//zhaodao x shendu wei d de zuxian
    	for(register int i=lg2(dep[x]-d);i>=0;i--) {
    		if(dep[anc[x][i]]>=d) {
    			x=anc[x][i];
    		}
    	}
    	return x;
    }
    inline int near_ch(const int &x,const int &y) {
    	//zhaodao x zuijin de zijiedian, bingqie shi y de zuxian
    	if(is_anc(x,y)) {
    		return jump(y,dep[x]+1);
    	} else {
    		return anc[x][0];
    	}
    }
    inline int count_leaves(const int &x) {
    	if(x==r) return leaf[1];
    	if(is_anc(x,r)) {
    		return leaf[1]-leaf[jump(r,dep[x]+1)];
    	} else {
    		return leaf[x];
    	}
    }
    class AuxTree {
    	//auxiliary tree
    	private:
    		int stk[N],top,cnt[N];
    		std::vector<int> e[N];
    		void add_edge(const int &u,const int &v) {
    			e[u].push_back(v);
    			e[v].push_back(u);
    		}
    	public:
    		void build(int s[],const int &r) {
    			const int n=s[0]+1;
    			s[n]=r;
    			std::sort(&s[1],&s[n]+1,
    				[](const int &i,const int &j) {
    					return dfn[i]<dfn[j];
    				}
    			);
    			stk[top=1]=s[1];
    			node.push_back(s[1]);
    			for(register int i=2;i<=n;i++) {
    				const int &x=s[i],p=lca(x,stk[top]);
    				while(dfn[p]<dfn[stk[top]]) {
    					if(dfn[p]>=dfn[stk[top-1]]) {
    						add_edge(p,stk[top--]);
    						if(stk[top]!=p) {
    							stk[++top]=p;
    							node.push_back(p);
    						}
    						break;
    					} else {
    						add_edge(stk[top],stk[top-1]);
    						top--;
    					}
    				}
    				stk[++top]=x;
    				node.push_back(x);
    			}
    			for(;top>1;top--) {
    				add_edge(stk[top],stk[top-1]);
    			}
    		}
    		void dfs(const int &x,const int &par) {
    			int tmp=0;
    			cnt[x]=x!=r&&e[x].size()==1;
    			for(auto &y:e[x]) {
    				if(y==par) continue;
    				dfs(y,x);
    				cnt[x]+=cnt[y];
    				tmp+=cnt[y]<count_leaves(near_ch(x,y));
    			}
    			if(tmp>2||(tmp==2&&cnt[x]!=s[0])) throw 0;
    		}
    		void clear() {
    			for(auto &x:node) {
    				e[x].clear();
    			}
    			node.clear();
    		}
    };
    AuxTree t;
    int main() {
    	const int n=getint(),m=getint();
    	for(register int i=1;i<n;i++) {
    		add_edge(getint(),getint());
    	}
    	dfs(1,0);
    	for(register int i=0;i<m;i++) {
    		r=getint();
    		for(register int i=0;i<=s[0];i++) {
    			s[i]=getint();
    		}
    		t.build(s,r);
    		try {
    			t.dfs(r,0);
    			puts("YES");
    		} catch(...) {
    			puts("NO");
    		}
    		t.clear();
    	}
    	return 0;
    }
    
  • 相关阅读:
    UnityEngine中Animator相关类的说明
    MecanimControl插件随笔
    Mecanim Control
    Unity3D
    Unity Mecanim在大型mmo中的应用
    Unity3D 性能优化
    Unity3D 图形优化
    U3D开发性能优化笔记(待增加版本.x)
    通过JS语句判断WEB网站的访问端是电脑还是手机
    jquery 鼠标事件汇总
  • 原文地址:https://www.cnblogs.com/skylee03/p/10186771.html
Copyright © 2020-2023  润新知