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

原文地址:https://www.cnblogs.com/chensunrise/p/3801635.html