zoukankan      html  css  js  c++  java
  • bzoj3306: 树(dfs序+倍增+线段树)

      比较傻逼的一道题...

      显然求子树最小值就是求出dfs序用线段树维护嘛

      换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论。

      如果询问的x是根就直接输出整棵树的最小值。

      如果询问的x是根在原树上的子节点,直接输出子树的最小值。

      如果询问的x是根在原树上的祖先,那么就要输出整棵树去掉x在原树上那个包含根的子节点的子树的答案。

      至于怎么求x在原树上那个包含根的子节点,可以用倍增。

      但是我发现直接遍历x的子节点居然不会被卡,而且还跑到了第一页嘿嘿嘿

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    const int maxn=500010, inf=1e9;
    struct poi{int too, pre;}e[maxn];
    struct tjm{int sum;}tree[maxn<<2];
    int n, q, x, y, tot, tott, root;
    int a[maxn], last[maxn], l[maxn], r[maxn], pos[maxn], d[maxn], f[maxn][20];
    char s[2];
    inline void read(int &k)
    {
        int f=1; k=0; char c=getchar();
        while(c<'0' || c>'9') c=='-' && (f=-1), c=getchar();
        while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
        k*=f;
    }
    inline void add(int x, int y){e[++tot].too=y; e[tot].pre=last[x]; last[x]=tot;}
    void dfs(int x)
    {
        l[x]=++tott; pos[tott]=x; d[x]=d[f[x][0]]+1;
        for(int i=last[x];i;i=e[i].pre) f[e[i].too][0]=x, dfs(e[i].too);
        r[x]=tott;
    }
    inline int min(int a, int b) {return a<b?a:b;}
    inline void up(int x) {tree[x].sum=min(tree[x<<1].sum, tree[x<<1|1].sum);}
    void build(int x, int l, int r)
    {
        if(l==r) {tree[x].sum=pos[l]?a[pos[l]]:inf; return;}
        int mid=(l+r)>>1;
        build(x<<1, l, mid); build(x<<1|1, mid+1, r);
        up(x);
    }
    void update(int x, int l, int r, int cx, int delta)
    {
        if(l==r) {tree[x].sum=delta; return;}
        int mid=(l+r)>>1;
        if(cx<=mid) update(x<<1, l, mid, cx, delta);
        else update(x<<1|1, mid+1, r, cx, delta);
        up(x);
    }
    int query(int x, int l, int r, int cl, int cr)
    {
        if(cl>cr) return inf;
        if(cl<=l && r<=cr) return tree[x].sum;
        int mid=(l+r)>>1, ans=inf;
        if(cl<=mid) ans=query(x<<1, l, mid, cl, cr);
        if(cr>mid) ans=min(ans, query(x<<1|1, mid+1, r, cl, cr));
        return ans;
    }
    inline int solve(int x)
    {
        if(x==root) return tree[1].sum;
        if(l[x]>l[root] || r[x]<l[root]) return query(1, 1, n, l[x], r[x]);
        int now=root;
        for(int i=16;i>=0;i--) if(d[f[now][i]]>x) now=f[now][i];
        return min(query(1, 1, n, 1, l[now]-1), query(1, 1, n, r[now]+1, n));
    }
    int main()
    {
        read(n); read(q);
        for(int i=1;i<=n;i++)
        {
            read(x); read(a[i]);
            if(x) add(x, i);
        }
        dfs(root=1); build(1, 1, n);
        for(int j=1;j<=16;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
        for(int i=1;i<=q;i++)
        {
            scanf("%s", s+1);
            if(s[1]=='V') read(x), read(y), update(1, 1, n, l[x], y);
            else if(s[1]=='E') read(root);
            else read(x), printf("%d
    ", solve(x));
        }
    }
    View Code
  • 相关阅读:
    客户端和Web Api服务的交互
    ASP.NET MVC4 validate验证遇到DateTime 类型的Bug(完整解决方案)
    不能说的秘密 一个很感人的爱情故事
    快五一了,申请了第一个Blog,哈哈。
    人生没有目标是可怕的。。。
    在.NET中使用SMTP发送邮件,有一些疑问
    smtp验证发邮件,今天好郁闷,终于解决了
    C#、.NET迷你音乐播放器(改进版)
    C#实现冒泡排序 堆栈 队列
    C#、.NET版邮件(群)发系统
  • 原文地址:https://www.cnblogs.com/Sakits/p/8006985.html
Copyright © 2011-2022 走看看