【bzoj4551】【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”时表示这是一个询问操作对于每次询问操作。


输出

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

 

样例输入

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


样例输出

1
2
2
1

 



题解

注意到在结点u上打标记其实就是把u和u的子树的值对u取max。然后我们可以在线段树上打上一个标记,表示这段区间对哪个数取了max,因为是单点查询,所以最后标记一定会下放到叶子结点,再把结点的值与标记取max即可。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=100000+50;
const int maxm=200000+50;

int n,fa[maxn],m,cnt,a[maxn],tot;
int fir[maxn],nex[maxm],to[maxm],wi[maxm],ecnt;
int top[maxn],son[maxn],dep[maxn],sz[maxn],id[maxn];

struct SegmentTree{int l,r,v,Max;}st[maxn<<2];

void add(int u,int v){
    nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;
}

void dfs1(int x,int f,int deep){
    fa[x]=f;dep[x]=deep;
    sz[x]=1;int maxson=-1;
    for(int e=fir[x];e;e=nex[e]){
        int v=to[e];
        if(v==f) continue;
        dfs1(v,x,deep+1);
        sz[x]+=sz[v];
        if(sz[v]>maxson) son[x]=v,maxson=sz[v];
    }
}

void dfs2(int x,int topf){
    top[x]=topf;
    id[x]=++tot;
    if(!son[x]) return ;
    dfs2(son[x],topf);
    for(int e=fir[x];e;e=nex[e]){
        int v=to[e];
        if(v==fa[x]||v==son[x]) continue;
        dfs2(v,v);
    }
}

void pushup(int root){
    st[root].v=st[root<<1].v+st[root<<1|1].v;
}

void build(int root,int l,int r){
    st[root].l=l;st[root].r=r;st[root].Max=-1;
    if(l==r) st[root].v=1;
    else{
        int m=l+r>>1;
        build(root<<1,l,m);build(root<<1|1,m+1,r);
        pushup(root);
    }
}

void pushdown(int root){
    if(st[root].Max!=-1){
        st[root<<1].Max=max(st[root<<1].Max,st[root].Max);
        st[root<<1|1].Max=max(st[root<<1|1].Max,st[root].Max);
        st[root].Max=-1;
    }
}

void addmark(int root,int l,int r,int M){
    if(st[root].l>r||st[root].r<l) return ;
    if(st[root].l>=l&&st[root].r<=r) st[root].Max=max(st[root].Max,M);
    else{
        pushdown(root);
        addmark(root<<1,l,r,M);addmark(root<<1|1,l,r,M);
        pushup(root);
    }
}

int query(int root,int l,int r){
    if(st[root].l>r||st[root].r<l) return 0;
    if(st[root].l>=l&&st[root].r<=r) return max(st[root].v,st[root].Max);
    pushdown(root);
    return query(root<<1,l,r)+query(root<<1|1,l,r);
}

template<typename T>void read(T& aa){
    char cc; ll ff;aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}

int main(){
    read(n),read(m);
    for(int i=1;i<n;i++){
        int x,y;
        read(x),read(y);
        add(x,y);add(y,x);
    }
    dfs1(1,0,1);dfs2(1,1);build(1,1,n);
    char c;int x;
    while(m--){
        cin>>c;
        if(c=='C'){
            read(x);
            addmark(1,id[x],id[x]+sz[x]-1,x);
        }
        else{
            read(x);
            printf("%d\n",query(1,id[x],id[x]));
        }
    }
    return 0;
}

 

posted @ 2018-10-18 18:40  rld  阅读(130)  评论(0编辑  收藏  举报