hdu3887

来源:互联网 发布:程序员比较拽的头像 编辑:程序博客网 时间:2024/06/10 03:18
/*
分析:
    ╮(╯▽╰)╭,昨天晚上见到了这个题,今天上午两节
课,一下课就到实验室刷这个题,愣是WA+OLT了俩小时。最
后无比郁闷的去上下午的两节课了,有一节还是体育、中午
还牟吃饭T^T,晚上的课直接翘掉,终于搞定这个题了。
    树状数组很早就会了,你说我得有多菜,囧~~~
    还意外的上了第一版,囧~,虽然倒数第二吧,囧~


    思路:
        10W的数据,杭电OJ用DFS的话必须会爆,所以就自
    己手动模拟栈吧(人才培养方案关于程序的只有一门C的、
    数据结构都要自己学的人儿,桑不起呀囧~)。
        然后DFS的过程中,每个节点都会有两次作为当前节
    点的时候,仔细想想,这两次之间的过程所扫描到的点,
    必定都是其子孙节点。那么,记录第一、二次扫描到这
    个节点的时候,树状数组C中,在其前面并且比它小的点
    的数量,则:ans[i]=num2[i]-num1[i]。
        而树状数组,在每一个节点要退出栈的时候,以这
    个元素更新一次(注意,如果让树状数组C[i]表示“<=”i
    的元素个数的话,那么要先得到num2[i],然后再更新,
    否则会计算自己的)。


    PS:暂时不会神马Cplusplus的容器,所以用的静态临街
    表。我做了一个小优化,用eage_now[节点[i]]来记录当
    前该扫描节点[i]的哪一条边了,省的重复调用前面已经
    搜索过的边。弱菜很囧~~~


                                          2012-10-16
*/










#include"stdio.h"#include"string.h"#include"stdlib.h"int n,root;int C[100011];int ans[100011];int hash[100011];int queue[100011];int eage_now[100011];struct Eage{int from,to,next;}eage[200011];int tot,head[100011];void add(int a,int b){eage[tot].from=a;eage[tot].to=b;eage[tot].next=head[a];head[a]=tot++;}int query(int k){int t=0;while(k>0){t+=C[k];k-=k&(-k);}return t;}void update(int k,int dir){while(k<=n && k>0){C[k]+=dir;k+=k&(-k);}}void DFS(){int z,i,j;int k=0;int flag;memset(hash,0,sizeof(hash));hash[root]=1;queue[++k]=root;ans[root]=0;for(i=0;i<=n;i++)eage_now[i]=head[i];while(k){flag=0;for(j=eage_now[queue[k]];j!=-1;j=eage[j].next){z=eage[j].to;if(hash[z])continue;eage_now[queue[k]]=eage[j].next;queue[++k]=z;hash[z]=1;ans[z]=query(z);flag=1;break;}if(flag==0){ans[queue[k]]=query(queue[k])-ans[queue[k]];update(queue[k],1);k--;}}}int main(){int i;int a,b;while(scanf("%d%d",&n,&root),n||root){tot=0;memset(head,-1,sizeof(head));for(i=1;i<n;i++){scanf("%d%d",&a,&b);add(a,b);add(b,a);}memset(C,0,sizeof(C));DFS();for(i=1;i<n;i++)printf("%d ",ans[i]);printf("%d\n",ans[n]);}return 0;}


原创粉丝点击