zoukankan      html  css  js  c++  java
  • BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述

    在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。

    输出

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

    样例输入

    5 5
    1 2
    1 3
    2 4
    2 5
    Q 2
    C 2
    Q 2
    Q 5
    Q 3

    样例输出

    1
    2
    2
    1
     
    这道题有两种做法(据说不止两种,本蒟蒻只会这两种qwq)。
    先来讲第一种:dfs序+线段树。
    假设我们对一个点进行了标记,那么可能会影响哪些点的答案?
    没错就是它的子树中所有点,因为一个点的子树在dfs序上是一段区间,我们以dfs序建线段树,每个点维护影响这个区间的深度最大的标记点是谁,那么每次修改时区间修改子树区间,将标记永久化,查询时单点查询,在线段树上沿途的标记中取深度最大的就是答案。
    再来说说比较麻烦的一种做法:树链剖分+线段树。
    对于线段树的每个点维护区间中被打标记的最深的点,每次修改时单点修改,查询时利用树链剖分往上爬重链,查询重链在线段树上的区间,只要有答案就输出。
    dfs序+线段树
    #include<set>
    #include<map>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,m;
    int x,y;
    int tot;
    int num;
    char ch[2];
    int f[100010];
    int s[100010];
    int d[100010];
    int t[100010];
    int to[200010];
    int mx[800010];
    int next[200010];
    int head[100010];
    void add(int x,int y)
    {
        tot++;
        next[tot]=head[x];
        head[x]=tot;
        to[tot]=y;
    }
    void dfs(int x)
    {
        s[x]=++num;
        d[x]=d[f[x]]+1;
        for(int i=head[x];i;i=next[i])
        {
            if(to[i]!=f[x])
            {
                f[to[i]]=x;
                dfs(to[i]);
            }
        }
        t[x]=num;
    }
    int cmp(int x,int y)
    {
        if(d[x]>d[y])
        {
            return x;
        }
        else
        {
            return y;
        }
    }
    void change(int rt,int l,int r,int L,int R,int k)
    {
        if(L<=l&&r<=R)
        {
            mx[rt]=cmp(mx[rt],k);
            return ;
        }
        int mid=(l+r)>>1;
        if(L<=mid)
        {
            change(rt<<1,l,mid,L,R,k);
        }
        if(R>mid)
        {
            change(rt<<1|1,mid+1,r,L,R,k);
        }
    }
    int query(int rt,int l,int r,int k)
    {
        if(l==r)
        {
            return mx[rt];
        }
        int mid=(l+r)>>1;
        int res=mx[rt];
        if(k<=mid)
        {
            return cmp(res,query(rt<<1,l,mid,k));
        }
        else
        {
            return cmp(res,query(rt<<1|1,mid+1,r,k));
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs(1);
        change(1,1,n,1,n,1);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",ch);
            scanf("%d",&x);
            if(ch[0]=='C')
            {
                change(1,1,n,s[x],t[x],x);
            }
            else
            {
                printf("%d
    ",query(1,1,n,s[x]));
            }
        }
    }

    树链剖分+线段树

    #include<set>
    #include<map>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,m;
    int x,y;
    int tot;
    int num;
    char ch[2];
    int f[100010];
    int s[100010];
    int d[100010];
    int q[100010];
    int to[200010];
    int mx[800010];
    int son[100010];
    int top[100010];
    int size[100010];
    int next[200010];
    int head[100010];
    void add(int x,int y)
    {
        tot++;
        next[tot]=head[x];
        head[x]=tot;
        to[tot]=y;
    }
    void dfs(int x)
    {
        d[x]=d[f[x]]+1;
        size[x]=1;
        for(int i=head[x];i;i=next[i])
        {
            if(to[i]!=f[x])
            {
                f[to[i]]=x;
                dfs(to[i]);
                size[x]+=size[to[i]];
                if(size[to[i]]>size[son[x]])
                {
                    son[x]=to[i];
                }
            }
        }
    }
    void dfs2(int x,int tp)
    {
        s[x]=++num;
        q[num]=x;
        top[x]=tp;
        if(son[x])
        {
            dfs2(son[x],tp);
        }
        for(int i=head[x];i;i=next[i])
        {
            if(to[i]!=f[x]&&to[i]!=son[x])
            {
                dfs2(to[i],to[i]);
            }
        }
    }
    int cmp(int x,int y)
    {
        if(d[x]>d[y])
        {
            return x;
        }
        else
        {
            return y;
        }
    }
    void pushup(int rt)
    {
        mx[rt]=cmp(mx[rt<<1],mx[rt<<1|1]);
    }
    void change(int rt,int l,int r,int k,int v)
    {
        if(l==r)
        {
            mx[rt]=v;
            return ;
        }
        int mid=(l+r)>>1;
        if(k<=mid)
        {
            change(rt<<1,l,mid,k,v);
        }
        else
        {
            change(rt<<1|1,mid+1,r,k,v);
        }
        pushup(rt);
    }
    int query(int rt,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R)
        {
            return mx[rt];
        }
        int mid=(l+r)>>1;
        if(L>mid)
        {
            return query(rt<<1|1,mid+1,r,L,R);
        }
        if(R<=mid)
        {
            return query(rt<<1,l,mid,L,R);
        }
        else
        {
            return cmp(query(rt<<1,l,mid,L,R),query(rt<<1|1,mid+1,r,L,R));
        }
    }
    int ask(int x)
    {
        int res;
        while(top[x]!=1)
        {
            res=query(1,1,n,s[top[x]],s[x]);
            if(res!=0)
            {
                return res;
            }
            x=f[top[x]];
        }
        res=query(1,1,n,1,s[x]);
        return res;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs(1);
        dfs2(1,1);
        change(1,1,n,1,1);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",ch);
            scanf("%d",&x);
            if(ch[0]=='C')
            {
                change(1,1,n,s[x],x);
            }
            else
            {
                printf("%d
    ",ask(x));
            }
        }
    }
  • 相关阅读:
    OSI七层模型详解 TCP/IP协议
    ZT 第一范式,第二范式,第三范式
    思杰20140522
    Correspondence / ˏkɔris'pɔndәns / dictionary10-800.doc
    闲着没事,贴贴图
    心情闲适,发几个tatanic的图
    005 Python 基础特性
    017 虚拟内存 64位及内存对其 3
    004 Python 文件操作 字典 自定义函数
    003 Python list 索引
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9764877.html
Copyright © 2011-2022 走看看