【bzoj4551】[Tjoi2016&Heoi2016]树 暴力?树剖+树状数组+二分

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”时表示这是一个询
问操作对于每次询问操作,1 ≤ N, Q ≤ 100000。

Output

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

Sample Input

5 5

1 2

1 3

2 4

2 5

Q 2

C 2

Q 2

Q 5

Q 3

Sample Output

1 

2 

2 

1

HINT

Source

好吧 标题的问号之后都是我BB的…最近好懒啊懒得写怎么办QAQ是不是要滚粗了

这个题居然暴力找爹就能进rank前五了…300ms……加强数据之后会马上就挂掉吧2333

自我感觉是剖一个,然后每次打标记是把当前节点到根节点的路径+1,然后查询的时候二分和祖先距离的深度,根据祖先的权值和当前点的权值调整边界……好像是三个log…不知道能不能过……

贴个暴力代码233

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

const int SZ = 200010;

int read()
{
    int n = 0;
    char a = getchar();
    bool flag = 0;
    while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
    while(a >= '0' && a <= '9') n = n * 10 + a - '0',a = getchar();
    if(flag) n = -n;
    return n;
}

int head[SZ],nxt[SZ],to[SZ];

void build(int f,int t)
{
    static int tot = 1;
    to[++ tot] = t;
    nxt[tot] = head[f];
    head[f] = tot;
}

int fa[SZ];

void dfs(int u,int f)
{
    fa[u] = f;
    for(int i = head[u];i;i = nxt[i])
        if(to[i] != f)
            dfs(to[i],u);
}

bool tag[SZ];

int main()
{
    int n = read(),m = read();
    for(int i = 1;i < n;i ++)
    {
        int a = read(),b = read();
        build(a,b); build(b,a);
    }
    tag[1] = 1;
    dfs(1,0);
    while(m --)
    {
        char opt[3];
        scanf("%s",opt);
        int u = read();
        if(opt[0] == 'Q')
        {
            while(!tag[u]) u = fa[u];
            printf("%d\n",u);
        }
        else
        {
            tag[u] = 1;
        }
    }
    return 0;
}

你可能感兴趣的:(【bzoj4551】[Tjoi2016&Heoi2016]树 暴力?树剖+树状数组+二分)