zoukankan      html  css  js  c++  java
  • hust 1016 Black-White Tree

    题目描述

    在图论中,包含n个结点(结点编号为1~n)、n-1条边的无向连通图被称为树。 在树中,任意一对结点间的简单路径总是惟一的。 你拥有一棵白色的树——所有节点都是白色的。接下来,你需要处理c条指令: 修改指令(0 v):改变一个给定结点的颜色(白变黑,黑变白); 查询指令(1 v):询问从结点1到一个给定结点所经过的第一个黑色结点编号(假设沿着简单路径走)。 注意,在查询指令中,必须从结点1而不是结点v出发。如果结点1本身就是黑色,查询指令应该返回1。

    输入

    第一行包含两个正整数n, c,即结点数和指令条数,n和c都不大于1,000,000. 以下n-1行,每行两个正整数(ui, vi) (1 <= ui < vi <= n),表示结点ui到vi之间有一条无向边。 以下c行,每行两个整数(c, v)。当c=0时表示修改指令,其中v代表被修改的结点编号;c=1时表示查询指令。 你的程序需要输出结点1到结点v之间路径的第一个黑色结点编号。 在第一条指令执行前,所有结点都是白色的。

    输出

    对于每个查询操作(c=1的操作),输出一行,包含一个整数,即第一个黑色结点的编号。如果不存在黑色结点,输出-1。样例输入

    9 8
    1 2
    1 3
    2 4
    2 9
    5 9
    7 9
    8 9
    6 8
    1 3
    0 8
    1 6
    1 7
    0 2
    1 9
    0 2
    1 9 
    

    样例输出

    -1
    8
    -1
    2
    -1 

    百度之星2008的题目,真的是一道超级好题啊,一开始怎么都不知道方法,后来看了某人的方法说进行路径压缩,就是有些链可以压缩一下,这样来求,于是写了一个,不过还是超时了,后来再无意中看到一份牛X的解法
    “以1为根建树,则题目问的就是每个点到根的路径中深度最小的黑色点。先dfs一次纪录每个点的入栈时间in[i]和出栈时间out[i]。注意dfs要用回溯法,要不会堆栈溢出,因为n最大为10^6。 
    根据v的祖先u有 in[u] < in[v] && out[v] < out[u] 的性质,先将所有节点按in[]序,然后用一个线段树维护按in[]排序后的out[] * color值(color=0表示白色,1表示黑色)。 
    对于题目的每个询问v。等价于在区间[1, rank[v]]里查找一个out[i]*color的最大值。rank[v]表示v按in排序后的位置),如果满足out[v] <= x则x对应的节点编号为答案(越大越靠近根,乘color用于排除白色节点的影响)。” 
    多么牛的解法啊,首先这个题如果知道这么做了,那就不是难题了,主要的是把dfs的递归转化成非递归,方法就是自己定义一个栈来模拟递归过程,其次的二分,线段树之类的就不用我说了,直接写就可以了,由于网上好像没有代码吧!贴一下我的代码,8000msAC的,其实还可以在优化,不过已经够了
    #include<map>
    #include<set>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define  inf 0x0f0f0f0f
    
    using namespace std;
    const int maxn=1000000+10;
    
    struct node
    {
         int col,in,out,id;
    }a[maxn];
    
    struct node2
    {
         int x,date;
    }b[maxn];
    
    struct node1
    {
         int L,R,mmax;
    }tree[maxn*4];
    
    vector<int>G[maxn];
    bool vis[maxn];
    bool cmp(node2 x,node2 y)
    {
         return x.date<y.date;
    }
    
    void dfs(int n)
    {
         stack<int>S;
         int dfs_clock=1,ID=1;
         a[1].col=0; a[1].in=1; vis[1]=true; a[1].id=1;
         S.push(1);
         while(!S.empty())
         {
              int u=S.top();
              bool cut=false;
              for (int i=0;i<G[u].size();i++)
              {
                   int v=G[u][i];
                   if (!vis[v])
                   {
                        cut=true;
                        dfs_clock++; ID++;
                        vis[v]=1;
                        a[v].col=0; a[v].in=dfs_clock;a[v].id=ID;
                        S.push(v);
                        break;
                   }
              }
              if (!cut)
              {
                   dfs_clock++;
                   S.pop();
                   a[u].out=dfs_clock;
              }
         }
    }
    
    void build(int c,int x,int y)
    {
         tree[c].L=x; tree[c].R=y; tree[c].mmax=0;
         if (x==y) return;
         int mid=x+(y-x)/2;
         build(c*2,x,mid);
         build(c*2+1,mid+1,y);
    }
    
    void update(int c,int x,int v)
    {
         if (tree[c].L==x && tree[c].R==x)
         {
              tree[c].mmax=v;
              return;
         }
         int mid=tree[c].L+(tree[c].R-tree[c].L)/2;
         if (x<=mid) update(c*2,x,v);
         else update(c*2+1,x,v);
         tree[c].mmax=max(tree[c*2].mmax,tree[c*2+1].mmax);
    }
    
    int get_max(int c,int x,int y)
    {
         if (tree[c].L==x && tree[c].R==y) return tree[c].mmax;
         int mid=tree[c].L+(tree[c].R-tree[c].L)/2;
         if (y<=mid) return get_max(c*2,x,y);
         else if(x>mid) return get_max(c*2+1,x,y);
         else
         {
              return max(get_max(c*2,x,mid),get_max(c*2+1,mid+1,y));
         }
    }
    
    void init(int n)
    {
         for (int i=0;i<=n;i++)
         {
              G[i].clear();
              vis[i]=0;
         }
    }
    
    int find(int x,int y,int v)
    {
         while(x<y)
         {
              int m=x+(y-x)/2;
              if (b[m].date>=v) y=m;
              else x=m+1;
         }
         return x;
    }
    
    int main()
    {
         int n,m,x,y;
         while (scanf("%d%d",&n,&m)!=EOF)
         {
              init(n);
              build(1,1,n);
              for (int i=1;i<n;i++)
              {
                   scanf("%d%d",&x,&y);
                   G[x].push_back(y);
                   G[y].push_back(x);
              }
              dfs(1);
              for (int i=1;i<=n;i++)
              {
                   b[i].x=i;
                   b[i].date=a[i].out;
              }
              sort(b+1,b+n+1,cmp);
              while(m--)
              {
                   scanf("%d%d",&x,&y);
                   if (x==0)
                   {
                        a[y].col=a[y].col^1;
                        int v=a[y].col*a[y].out;
                        update(1,a[y].id,v);
                   }
                   else
                   {
                        int ans=get_max(1,1,a[y].id);
                        if (ans==0 || ans<a[y].in) printf("-1
    ");
                        else printf("%d
    ",b[find(1,n,ans)].x);
                   }
              }
         }
         return 0;
    }

    作者 chensunrise

  • 相关阅读:
    经过改良后可以导出超过70000条数据的导出公共excel类
    一个简单的文档导出公共处理类
    网上找的正则验证邮箱手机等代码
    springMvc IE浏览器 前台中文参数 乱码问题解决方法
    国际化
    验证框架
    基于注解来装配Bean的属性
    aop
    自定义属性编辑器
    propertyPlaceholderConfigurer 和propertyOverrideConfigurer
  • 原文地址:https://www.cnblogs.com/chensunrise/p/3801635.html
Copyright © 2011-2022 走看看