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;
}

 

posted @ 2018-01-04 17:01  Elfish?  阅读(235)  评论(2编辑  收藏  举报