bzoj 4551: [Tjoi2016&Heoi2016]树 (线段树)

来源:互联网 发布:ubuntu 当前目录大小 编辑:程序博客网 时间:2024/09/21 09:18

题目描述

传送门

题解

感觉这道题写法其实应该挺多的,我写的线段树的区间修改单点查询,然后用的标记永久化。。

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#define N 200003using namespace std;int tot,point[N],nxt[N],v[N],l[N],r[N];int tr[N*4],delta[N*4],deep[N],n,m,sz;int add(int x,int y){    tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;    tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void dfs(int x,int fa){    deep[x]=deep[fa]+1;    l[x]=++sz;     for (int i=point[x];i;i=nxt[i]) {        if (v[i]==fa) continue;        dfs(v[i],x);    }    r[x]=sz;}void build(int now,int l,int r){    if (l==r) {        tr[now]=1; delta[now]=1;        return;    }    int mid=(l+r)/2;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);}void query(int now,int l,int r,int ll,int rr,int x){    if (ll<=l&&r<=rr) {        if(deep[delta[now]]<deep[x])  delta[now]=x;        return;    }    int mid=(l+r)/2;    if (ll<=mid) query(now<<1,l,mid,ll,rr,x);    if (rr>mid) query(now<<1|1,mid+1,r,ll,rr,x);}int find(int now,int l,int r,int x){    if (l==r) return delta[now];    int mid=(l+r)/2;    int ans=delta[now]; int t=0;    if (x<=mid) t=find(now<<1,l,mid,x);    else t=find(now<<1|1,mid+1,r,x);    if (deep[ans]>deep[t]) return ans;    else return t;}int main(){    freopen("a.in","r",stdin);    scanf("%d%d",&n,&m);    for (int i=1;i<n;i++) {        int x,y; scanf("%d%d",&x,&y);        add(x,y);    }    dfs(1,0);    build(1,1,n);    for (int i=1;i<=m;i++) {        char s[5]; int x; scanf("%s%d",s+1,&x);         if (s[1]=='C') query(1,1,n,l[x],r[x],x);        else printf("%d\n",find(1,1,n,l[x]));    }}
0 0