zoukankan      html  css  js  c++  java
  • BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树

    BZOJ_4551_[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
     

    标记的时候直接标该点在dfs序中的位置。
    然后查询时查从根到这个点路径上点权最大值。
    因为dfs序的性质,可以保证最大的一定离这个点最近。
    然后树剖+线段树搞搞。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 200050
    #define ls p<<1
    #define rs p<<1|1
    int c[N<<2],a[N],n,m,dep[N],fa[N],son[N],idx[N],top[N];
    int head[N],to[N<<1],nxt[N<<1],cnt,siz[N],tot,sec,d[N];
    char opt[10];
    inline void add(int u,int v) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void dfs1(int x,int y) {
        a[x]=++sec;
        d[sec]=x;
        dep[x]=dep[y]+1;
        fa[x]=y;
        siz[x]=1;
        int i;
        for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
            dfs1(to[i],x);
            siz[x]+=siz[to[i]];
            if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
        }
    }
    void dfs2(int x,int t) {
        top[x]=t; idx[x]=++tot;
        int i;
        if(son[x]) dfs2(son[x],t);
        for(i=head[x];i;i=nxt[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) dfs2(to[i],to[i]);
    }
    void update(int l,int r,int x,int v,int p) {
        if(l==r) {
            c[p]=v; return ;
        }
        int mid=(l+r)>>1;
        if(x<=mid) update(l,mid,x,v,ls);
        else update(mid+1,r,x,v,rs);
        c[p]=max(c[ls],c[rs]);
    }
    int qmx(int l,int r,int x,int y,int p) {
        if(x<=l&&y>=r) return c[p];
        int mid=(l+r)>>1,re=0;
        if(x<=mid) re=max(re,qmx(l,mid,x,y,ls));
        if(y>mid) re=max(re,qmx(mid+1,r,x,y,rs));
        return re;
    }
    int main() {
        scanf("%d%d",&n,&m);
        int i,x,y;
        for(i=1;i<n;i++) {
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        dfs1(1,0);
        dfs2(1,1);
        update(1,n,idx[1],1,1);
        while(m--) {
            scanf("%s%d",opt,&x);
            if(opt[0]=='Q') {
                y=1;
                int ans=0;
                while(top[x]!=top[y]) {
                    if(dep[top[x]]>dep[top[y]]) swap(x,y);
                    ans=max(ans,qmx(1,n,idx[top[y]],idx[y],1));
                    y=fa[top[y]];
                }
                if(dep[x]<dep[y]) swap(x,y);
                ans=max(ans,qmx(1,n,idx[y],idx[x],1));
                printf("%d
    ",d[ans]);
            }else {
                update(1,n,idx[x],a[x],1);
            }
        }
    }
    
    
  • 相关阅读:
    第一章:linux命令初步
    请教shell读写XML问题(转)
    讓 BootCamp 下的 Windows XP 也能有 D 硬碟槽(转)
    Linux下的多线程编程(转)
    怎么查看redhat版本
    不透過 Boot Camp 安裝 Windows 7,並切割成多個磁碟槽(转)
    同位语从句用法详解
    更改linux的最大文件描述符限制
    ObjectiveC中 copy, tetain, assign , readonly , readwrite, nonatomic区别
    Linux如何查找文件安装路径
  • 原文地址:https://www.cnblogs.com/suika/p/8742652.html
Copyright © 2011-2022 走看看