zoukankan      html  css  js  c++  java
  • 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
Copyright © 2011-2022 走看看