zoukankan      html  css  js  c++  java
  • BZOJ4551: [Tjoi2016&Heoi2016]树

    【传送门:BZOJ4551


    简要题意:

      给出一棵树,根节点为1,一开始根节点打了标记,给出q个操作,有两种操作:

      第一种输入Q x,求出离x最近的打了标记的祖先  

      第二种输入C x,将x点打标记


    题解:

      树链剖分水题

      首先因为重链上的点的新编号是连续的,所以当我们求离x最近的打了标记的祖先时,就找x上面的打了标记而且新编号最大的点(因为重链上,深度越深,编号越大)

      然后每个线段树区间的c值,就是打了标记编号最大的点的编号


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    struct node
    {
        int x,y,next;
    }a[110000];int len,last[110000];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len;
    }
    struct trnode
    {
        int l,r,lc,rc,c;
    }tr[210000];int trlen;
    void bt(int l,int r)
    {
        trlen++;int now=trlen;
        tr[now].l=l;tr[now].r=r;tr[now].c=-1;
        tr[now].lc=tr[now].rc=-1;
        if(l<r)
        {
            int mid=(l+r)/2;
            tr[now].lc=trlen+1;bt(l,mid);
            tr[now].rc=trlen+1;bt(mid+1,r);
        }
    }
    int tot[110000],dep[110000],fa[110000],son[110000];
    void pre_tree_node(int x)
    {
        tot[x]=1;son[x]=0;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fa[x])
            {
                fa[y]=x;
                dep[y]=dep[x]+1;
                pre_tree_node(y);
                tot[x]+=tot[y];
                if(tot[y]>tot[son[x]]) son[x]=y;
            }
        }
    }
    int top[110000],ys[110000],z;
    int pp[110000];
    void pre_tree_edge(int x,int tp)
    {
        ys[x]=++z;pp[z]=x;top[x]=tp;
        if(son[x]!=0) pre_tree_edge(son[x],tp);
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fa[x]&&y!=son[x]) pre_tree_edge(y,y);
        }
    }
    void change(int now,int x)
    {
        if(tr[now].l==tr[now].r){tr[now].c=x;return ;}
        int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
        if(x<=mid) change(lc,x);
        else change(rc,x);
        tr[now].c=max(tr[lc].c,tr[rc].c);
    }
    int near(int now,int l,int r)
    {
        if(tr[now].l==l&&tr[now].r==r) return tr[now].c;
        int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
        if(r<=mid) return near(lc,l,r);
        else if(l>mid) return near(rc,l,r);
        else return max(near(lc,l,mid),near(rc,mid+1,r));
    }
    int solve(int x)
    {
        int tp=top[x];
        int ans=0;
        while(1)
        {
            int t=near(1,ys[tp],ys[x]);
            if(t==-1)
            {
                x=fa[tp];
                tp=top[x];
            }
            else return pp[t];
        }
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            ins(x,y);
        }
        dep[1]=0;fa[1]=0;pre_tree_node(1);
        z=0;pre_tree_edge(1,1);
        trlen=0;bt(1,z);
        change(1,ys[1]);
        char st[3];
        for(int i=1;i<=m;i++)
        {
            int x;
            scanf("%s%d",st+1,&x);
            if(st[1]=='Q') printf("%d
    ",solve(x));
            else change(1,ys[x]);
        }
        return 0;
    }

     

  • 相关阅读:
    HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
    HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
    POJ 3974 Palindrome【manacher】【模板题】【模板】
    POJ 3974 Palindrome【manacher】【模板题】【模板】
    HDU 6127 Hard challenge【计算机几何】【思维题】
    HDU 6127 Hard challenge【计算机几何】【思维题】
    HDU 6129 Just do it【杨辉三角】【思维题】【好题】
    HDU 6129 Just do it【杨辉三角】【思维题】【好题】
    HDU 3037 Saving Beans【Lucas定理】【模板题】【模板】【组合数取余】
    8.Math 对象
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8548697.html
Copyright © 2011-2022 走看看