暴力 【p4092】[HEOI2016/TJOI2016]树

Description

在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:

  1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记。)
  2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先)

你能帮帮他吗?

Input

输入第一行两个正整数N和Q分别表示节点个数和操作次数

接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v有一条有向边

接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询问操作对于每次询问操作。

Output

输出一个正整数,表示结果。

令人窒息的一个题,洛谷上暴力\(A\)了?

但是bzoj上T的飞起 emm

听学长说,这题是树剖。

但是暴力\(A\)掉了。于是写正解就向后拖一拖 emmm

小优化:如果没有修改操作,直接输出\(1\)

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define R register

using namespace std;

const int gz=100008;

inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}

int n,q;

int f[gz],tg[gz];


char opt[5];

inline int work(R int x)
{
    if(tg[x])return x;
    while(f[x])
    {
        x=f[x];
        if(tg[x])return x;
    }
}

bool flg;

int main()
{
    in(n),in(q);
    for(R int i=1,x,y;i<n;i++)
        in(x),in(y),f[y]=x;
    tg[1]=true;
    for(R int i=1,x;i<=q;i++)
    {
        scanf("%s",opt+1);
        if(opt[1]=='Q')
        {
            in(x);
            if(!flg)puts("1");
            else printf("%d\n",work(x));
        }
        else
        {
            in(x),flg=true;
            tg[x]=true;
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/-guz/p/9879179.html