首页 > 代码库 > hust 1016 Black-White Tree

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 81 21 32 42 95 97 98 96 81 30 81 61 70 21 90 21 9 

样例输出

-18-12-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 0x0f0f0f0fusing 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\n");                    else printf("%d\n",b[find(1,n,ans)].x);               }          }     }     return 0;}

作者 chensunrise