bzoj4551 [HEOI2016]树
题目描述
在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下
两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个
结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
先)你能帮帮他吗?
输入格式
输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v
有一条有向边接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询
问操作对于每次询问操作,1 ≤ N, Q ≤ 100000。
输出格式
输出一个正整数,表示结果
题解
我用的方法就是直接暴力,至少考试和bz上的数据都过了。就是每次有一个没有标记的点被打上标记了,就从这个点往下搜索,如果他的儿子已有标记就跳过这个儿子。综合复杂度O(n)(大概?)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 int n,m; int cnt,head[maxn]; struct edge{ int next,to; }e[maxn*2]; char ch[2]; int ans[maxn]; bool ok[maxn],vis[maxn]; void insert(int u,int v){ cnt++; e[cnt].next=head[u];e[cnt].to=v; head[u]=cnt; } void dfs(int x){ for(int i=head[x];i;i=e[i].next){ int to=e[i].to; if(ok[to]){ continue; } else{ ans[to]=ans[x]; dfs(to); } } } int main(){ // freopen("tree.in","r",stdin); // freopen("tree.out","w",stdout); scanf("%d%d",&n,&m); ok[1]=1; int u,v,k; for(int i=1;i<=n;i++){ scanf("%d%d",&u,&v); insert(u,v); } for(int i=1;i<=n;i++)ans[i]=1; for(int i=1;i<=m;i++){ scanf("%s",ch); scanf("%d",&k); if(ch[0]=='C'){ if(!ok[k]) { ok[k]=1; ans[k]=k; dfs(k); } } else{ printf("%d\n",ans[k]); } } return 0; }