[CC-ADJLEAF2]Adjacent Leaves

[CC-ADJLEAF2]Adjacent Leaves

题目大意:

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

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

思路:

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

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

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

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

由于\(\sum|S|\le5\times10^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;
}
posted @ 2018-12-27 18:59  skylee03  阅读(135)  评论(0编辑  收藏  举报