bzoj4551 [Tjoi2016&Heoi2016]树

http://www.elijahqi.win/archives/2938
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
HINT

新加数据9组(By HFLSyzx ),未重测–2016.8.2

Source

直接把get 写成max官方数据竟然ac了 我也是很无语..有空给洛谷加强下数据吧..

#include<cstdio>
#include<cctype>
#define N 100010
#define lc (x<<1)
#define rc (x<<1|1)
#include<algorithm>
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if(T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int out_len=1<<16;
char obuf[out_len],*oh=obuf;
inline void write_char(char c){
    if (oh==obuf+out_len) fwrite(obuf,1,out_len,stdout),oh=obuf;
    *oh++=c;
}
template<class T>
inline void W(T x){
    static int buf[30],cnt;
    if (!x) write_char('0');else{
        if (x<0) write_char('-'),x=-x;
        for (cnt=0;x;x/=10) buf[++cnt]=x%10+48;
        while(cnt) write_char(buf[cnt--]);
    }
}
inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
struct node1{
    int y,next;
}data[N<<1];
struct node{
    int id,tag;
}tree[N<<2];
int num,h[N],in[N],out[N],n,s[N],q,dep[N];
inline void dfs(int x,int fa){
    in[x]=++num;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if(y==fa) continue;
        dep[y]=dep[x]+1;dfs(y,x);
    }out[x]=num;
}
inline int get(int x,int y){return dep[x]>dep[y]?x:y;}
inline void pushdown(int x){
    if (!tree[x].tag) return;static int tmp;tmp=tree[lc].id;
    tree[lc].id=get(tree[lc].id,tree[x].id);if (tmp!=tree[lc].id) tree[lc].tag=tree[lc].id;
    tmp=tree[rc].id;tree[rc].id=get(tree[rc].id,tree[x].id);
    if (tmp!=tree[rc].id) tree[rc].tag=tree[rc].id;tree[x].tag=0;
}
inline void modify(int x,int l,int r,int l1,int r1,int v){
    if (l1<=l&&r1>=r) {int tmp=tree[x].id;tree[x].id=get(tree[x].id,v);
    if(tree[x].id!=tmp) tree[x].tag=v;return;}int mid=l+r>>1;pushdown(x);
    if (l1<=mid) modify(lc,l,mid,l1,r1,v);
    if (r1>mid) modify(rc,mid+1,r,l1,r1,v); 
}
inline int query(int x,int l,int r,int p){
    if(l==r) return tree[x].id;int mid=l+r>>1;pushdown(x);
    if(p<=mid) return query(lc,l,mid,p);else return query(rc,mid+1,r,p);
}
int main(){
    freopen("bzoj4551.in","r",stdin);
    n=read();q=read();
    for (int i=1;i<n;++i){
        int x=read(),y=read();
        data[++num].y=y;data[num].next=h[x];h[x]=num;
        data[++num].y=x;data[num].next=h[y];h[y]=num;
    }num=0;dfs(1,1);modify(1,1,n,in[1],out[1],1);
    for (int i=1;i<=q;++i){static char ch;static int x;
        ch=gc();while(ch!='Q'&&ch!='C') ch=gc();
        if(ch=='Q'){
            x=read();W(query(1,1,n,in[x]));write_char('\n');continue;
        }x=read();modify(1,1,n,in[x],out[x],x);
    }flush();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值