P4092 [HEOI2016/TJOI2016]树

题目描述

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

  1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记。)

  2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先)

你能帮帮他吗?

输入输出格式

输入格式:

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

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

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

输出格式:

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

输入输出样例

输入样例#1: 复制
5 5 
1 2 
1 3 
2 4 
2 5 
Q 2 
C 2 
Q 2 
Q 5 
Q 3
输出样例#1: 复制
1
2
2
1

说明

30%的数据,1 ≤ N, Q ≤ 1000

70%的数据,1 ≤ N, Q ≤ 10000

100%的数据,1 ≤ N, Q ≤ 100000

// luogu-judger-enable-o2
//其实不是树剖,而是dfs序+线段树
//每个点的dfs序是一段区间,这段区间就是它的孩子们
//当我们更改一个点的时候,就把它的孩子们全改了 (要判断一下改不改)
//如果它的儿子们的num(要求的祖先)的dep小于lazy的deep,就修改它的儿子们的lazy和num,改成当前点的lazy
//否则就不改   这样就避免了后来的标记覆盖了之前的标记  而且我们的标记一定是当前最优的 

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

const int N=1e5+5;

int n,m;
int opt,x;
int head[N],num_edge;
struct Edge
{
    int v,nxt;
}edge[N<<1];
struct Node
{
    int fa,son;
    int s,t;
    int size;
    int dep,top;
}node[N];
struct TREE
{
    TREE *lson,*rson;
    int l,r,mid;
    int num,lazy;
}tree[N<<2];

typedef TREE* Tree;
Tree Root,now_node=tree;

inline int read()
{
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='C') return 1;
        else if(c=='Q')    return 2;
    int num=0;
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num;
}

inline void add_edge(int u,int v)
{
    edge[++num_edge].v=v;
    edge[num_edge].nxt=head[u];
    head[u]=num_edge;
}

void dfs1(int u)
{
    node[u].size=1;
    for(int i=head[u],v;i;i=edge[i].nxt)
    {
        v=edge[i].v;
        if(v==node[u].fa)
            continue;
        node[v].fa=u;
        node[v].dep=node[u].dep+1;
        dfs1(v);
        node[u].size+=node[v].size;
        if(node[v].size>node[node[u].son].size)
            node[u].son=v;
    }
}

int bound;
void dfs2(int u)
{
    node[u].s=++bound;
    if(node[u].son)
    {
        dfs2(node[u].son);
        for(int i=head[u],v;i;i=edge[i].nxt)
        {
            v=edge[i].v;
            if(v==node[u].fa||v==node[u].son)
                continue;
            dfs2(v);
        }
    }
    node[u].t=bound;
}

void build(Tree &root,int l,int r)
{
    root=++now_node;
    root->l=l,root->r=r,root->mid=l+r>>1;
    root->num=1;
    if(l==r)
        return;
    build(root->lson,l,root->mid);
    build(root->rson,root->mid+1,r);
}

inline void pushdown(Tree root)
{
    if(root->lazy)
    {
        if(node[root->lazy].dep>node[root->lson->lazy].dep)
            root->lson->lazy=root->lazy;
        if(node[root->lazy].dep>node[root->rson->lazy].dep)
            root->rson->lazy=root->lazy;
        if(node[root->lazy].dep>node[root->lson->num].dep)
            root->lson->num=root->lazy;
        if(node[root->lazy].dep>node[root->rson->num].dep)
            root->rson->num=root->lazy;
        root->lazy=0;
    }
}

void update(Tree root,int l,int r,int val)
{
    if(l==root->l&&r==root->r)
    {
        root->num=node[root->num].dep>node[val].dep?root->num:val;        //这儿也要比较一下的,一开始没比较,直接改的 
        root->lazy=node[root->lazy].dep>node[val].dep?root->lazy:val;    //因为这个区间不一定只改一次,所以也要比较  当时抽了 
        return;
    }
    pushdown(root);
    if(r<=root->mid)
        update(root->lson,l,r,val);
    else if(l>root->mid)
        update(root->rson,l,r,val);
    else
    {
        update(root->lson,l,root->mid,val);
        update(root->rson,root->mid+1,r,val);
    }
}

int query(Tree root,int pos)
{
    if(root->l==root->r)
        return root->num;
    pushdown(root);
    if(pos<=root->mid)
        return query(root->lson,pos);
    else
        return query(root->rson,pos);
}

int main()
{
    n=read(),m=read();
    for(int i=1,u,v;i<n;++i)
    {
        u=read(),v=read();
        add_edge(u,v);
        add_edge(v,u);
    }
    dfs1(1);
    dfs2(1);
    build(Root,1,n);
    for(int i=1;i<=m;++i)
    {
        opt=read(),x=read();
        if(opt==1)
            update(Root,node[x].s,node[x].t,x);
        else
            printf("%d
",query(Root,node[x].s));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lovewhy/p/8544589.html