zoukankan      html  css  js  c++  java
  • BZOJ 4551[Tjoi2016&Heoi2016]树(树链剖分+二分)

    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

    题解:感觉树链剖分的思路还是很好想的,一个点的祖宗肯定在它到根的路径里,我们可以令每个打标记的点权值为一,对于每条完整的链统计区间和,如果大于零,说明这段区间上至少有一个打了标记的点,对于这段区间,求出后一段的前缀和,如果是0,搜索前一段,否则搜索后一段.这是一种二分的思路.

    代码如下:

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define lson root<<1
    #define rson root<<1|1
    using namespace std;
    
    struct node
    {
        int sum,l,r;
    }tr[400040];
    int deep[100010],fa[100010],size[100010],son[100010],w[100010],iid[100010],id[100010],c[100010],top[100010],cnt;
    vector<int> g[100010];
    
    void push_up(int root)
    {
        tr[root].sum=tr[lson].sum+tr[rson].sum;
    }
    
    void build(int root,int l,int r)
    {
        if(l==r)
        {
            tr[root].l=l;
            tr[root].r=r;
            tr[root].sum=w[l];
            return ;
        }
        tr[root].l=l;
        tr[root].r=r;
        int mid=(l+r)>>1;
        build(lson,l,mid);
        build(rson,mid+1,r);
        push_up(root);
    }
    
    
    void update(int root,int x,int val)
    {
        if(x==tr[root].l&&x==tr[root].r)
        {
            tr[root].sum=val;
            return ;
        }
        int mid=(tr[root].l+tr[root].r)>>1;
        if(x<=mid)
        {
            update(lson,x,val);
        }
        else
        {
            update(rson,x,val);
        }
        push_up(root);
    }
    
    int query(int root,int l,int r)
    {
        if(l==tr[root].l&&tr[root].r==r)
        {
            return tr[root].sum;
        }
        int mid=(tr[root].l+tr[root].r)>>1;
        if(l>mid)
        {
            return query(rson,l,r);
        }
        else
        {
            if(r<=mid)
            {
                return query(lson,l,r);
            }
        }
        return query(lson,l,mid)+query(rson,mid+1,r);
    }
    
    void dfs1(int now,int f,int dep)
    {
        deep[now]=dep;
        fa[now]=f;
        size[now]=1;
        int maxson=-1;
        for(int i=0;i<g[now].size();i++)
        {
            if(g[now][i]==f)
            {
                continue;
            }
            dfs1(g[now][i],now,dep+1);
            size[now]+=size[g[now][i]];
            if(maxson<size[g[now][i]])
            {
                maxson=size[g[now][i]];
                son[now]=g[now][i];
            }
        }
    }
    
    void dfs2(int now,int topf)
    {
        id[now]=++cnt;
        iid[cnt]=now;
        w[cnt]=c[now];
        top[now]=topf;
        if(!son[now])
        {
            return;
        }
        dfs2(son[now],topf);
        for(int i=0;i<g[now].size();i++)
        {
            if(g[now][i]==son[now]||g[now][i]==fa[now])
            {
                continue;
            }
            dfs2(g[now][i],g[now][i]);
        }
    }
    
    int check(int l,int r)
    {
        if(l==r)
        {
            return l;
        }
        int mid=(l+r)>>1;
        int tmp=query(1,mid+1,r);
        if(tmp)
        {
            return check(mid+1,r);
        }
        else
        {
            return check(l,mid);
        }
    }
    
    int path_query(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])
            {
                swap(x,y);
            }
            int tmp=query(1,id[top[x]],id[x]);
            if(!tmp)
            {
                x=fa[top[x]];
            }
            else
            {
                return check(id[top[x]],id[x]);
            }
        }
        if(deep[x]>deep[y])
        {
            swap(x,y);
        }
        return check(id[x],id[y]);
    }
    
    int main()
    {
        int n,m,vv;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n-1;i++)
        {
            int from,to;
            scanf("%d%d",&from,&to);
            g[from].push_back(to);
            g[to].push_back(from);
        }
        c[1]=1;
        dfs1(1,0,1);
        dfs2(1,1);
        build(1,1,n);
        char c;
        for(int i=1;i<=m;i++)
        {
            scanf("
    %c %d",&c,&vv);
            if(c=='C')
            {
                update(1,id[vv],1);
            }
            if(c=='Q')
            {
                printf("%d
    ",iid[path_query(1,vv)]);
            }
        }
    }
  • 相关阅读:
    LCPhash求解
    BSGS
    洛谷—— P1849 [USACO12MAR]拖拉机Tractor
    BZOJ——2101: [Usaco2010 Dec]Treasure Chest 藏宝箱
    洛谷—— P1561 [USACO12JAN]爬山Mountain Climbing
    BZOJ——1601: [Usaco2008 Oct]灌水
    洛谷—— P1342 请柬
    [SDOI2009]Elaxia的路线 SPFA+Topo
    1737 配对
    51Nod 1378 夹克老爷的愤怒
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/8657907.html
Copyright © 2011-2022 走看看