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

    xiaoxiao2021-04-14  56

    题目描述

    传送门

    题解

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

    代码

    #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define N 200003 using 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])); } }
    转载请注明原文地址: https://ju.6miu.com/read-669912.html

    最新回复(0)