zoukankan      html  css  js  c++  java
  • POJ 3321:Apple Tree + HDU 3887:Counting Offspring(DFS序+树状数组)

    http://poj.org/problem?id=3321

    http://acm.hdu.edu.cn/showproblem.php?pid=3887

    POJ 3321:

    题意:给出一棵根节点为1的边不一定的树,然后给出问题:询问区间和 或者 节点值更新。

    HDU 3887:

    题意:和POJ 3321的题意差不多,只不过对每个节点询问不包含该节点的区间和


    思路:今天才学了下才知道有DFS序这种东西,加上树状数组处理一下区间和 和 节点更新。


    DFS序大概就是我们在DFS遍历一棵树的时候,在进入这个节点的时候,我们用一个变量记录此时的时间(代码中用cnt表示,也是可以看做是目前已经遍历过的节点的数目),
    然后分别用一个数组表示开始搜索这个节点的时间,和离开这个节点的时间(代码中用st代表开始,用ed代表结束)。然后我们可以发现在这段时间里面遍历过的节点都是该节点的儿子,即例如HDU3887这组样例:


    15 7
    7 10
    7 1
    7 9
    7 3
    7 4
    10 14
    14 2
    14 13
    9 11
    9 6
    6 5
    6 8
    3 15
    3 12
    0 0


    我们的遍历顺序是这样的:7 1 1 3 15 15 12 12 3 4 4 10 14 2 2 13 13 14 10 9 11 11 6 5 5 8 8 6 9 7(手打的。。)
    分别对应的下标是这样的:例如根节点7,它管辖的范围从前到后全部是,说明它就是根节点了。那么它的范围是【1,30】。

     1 int cnt = 0;
     2 void dfs(int u, int fa)
     3 {
     4     que[++cnt] = u;
     5     for(int k = head[u]; ~k; k = edge[k].nxt){
     6         int v = edge[k].v;
     7         if( v == fa ) continue;
     8         dfs(v, u);
     9     }
    10     que[++cnt] = u;
    11 }
    12 dfs(7, -1);
    我这里用的是前向星存的图,然后从根节点7开始遍历。
    我先用一个数组来装遍历过的点的顺序,即que数组为我上面列出来的那个序列。
    然后我们就按下面这样处理
    1 for(int i = 1; i <= cnt; i++) {
    2     if( st[que[i]] == 0 ) st[que[i]] = i;
    3     else se[que[i]] = i;
    4 }
    把开始的位置和结束的位置分别装在st数组和ed数组中。
    然后我们就可以根据这些条件建立起树状数组了。
    询问的区间和为Query( ed[node] ) - Query( st[node] - 1 ) / 2(因为我们重复计数了,每个节点枚举了两次) ,更新就是Update( ed[node], value ); Update( st[node], value );
    下面给出HDU 3887 的代码。
      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <vector>
      6 using namespace std;
      7 #define N 100010
      8 
      9 int st[N], se[N], ans[N], cnt;
     10 int bit[2*N],que[2*N];
     11 int head[N], tot;
     12 struct node
     13 {
     14     int v, nxt;
     15 }edge[N*2];
     16 //vector <int> edge[N];
     17 //dfs序 + 树状数组
     18 void addedge(int u, int v)
     19 {
     20     edge[tot].v = v;
     21     edge[tot].nxt = head[u];
     22     head[u] = tot++;
     23 }
     24 
     25 void dfs(int u, int fa)
     26 {
     27     que[++cnt] = u;
     28     for(int k = head[u]; ~k; k = edge[k].nxt){
     29         int v = edge[k].v;
     30         if( v == fa ) continue;
     31         dfs(v, u);
     32     }
     33     que[++cnt] = u;
     34 }
     35 
     36 int lowbit(int x)
     37 {
     38     return x & (-x);
     39 }
     40 
     41 void Update(int x, int value)
     42 {
     43     while( x <= cnt ) {
     44         bit[x] += value;
     45         x += lowbit(x);
     46     }
     47 }
     48 
     49 int Query(int x)
     50 {
     51     int ans = 0;
     52     while( x > 0 ) {
     53         ans += bit[x];
     54         x -= lowbit(x);
     55     }
     56     return ans;
     57 }
     58 
     59 int main()
     60 {
     61     int n,p;
     62     while(scanf("%d%d", &n, &p), n + p) {
     63 
     64         memset(head, -1, sizeof(head));
     65         tot = 0;
     66 
     67         memset(bit,0,sizeof(bit));
     68         memset(st,0,sizeof(st));
     69 //        for(int i = 1; i <= n; i++)
     70 //            edge[i].clear();
     71         for(int i = 1; i < n; i++) {
     72             int u, v;
     73             scanf("%d%d", &u, &v);
     74             addedge(u, v);
     75             addedge(v, u);
     76 //            edge[u].push_back(v);
     77 //            edge[v].push_back(u);
     78         }
     79         cnt = 0;
     80         dfs(p, p);
     81 
     82         for(int i = 1; i <= cnt; i++) {
     83             if( st[que[i]] == 0 ) st[que[i]] = i;
     84             else se[que[i]] = i;
     85         }
     86 
     87         for(int i = 1; i <= cnt; i++) {
     88 //            printf("%d  ", que[i]);
     89             Update(i, 1);
     90         }
     91         putchar('
    ');
     92 //因为题意中要求子树中的节点不能比根节点的数大,因此从后往前枚举,
     93 //然后删除掉枚举过的节点,这样就能保证后面的枚举中子树的点的数不会比根节点的大了
     94 //而且题目的询问是不包含该询问的节点的,因此是(Query(se[i] - 1) - Query(st[i])) / 2
     95 //而不是( Query(se[i]) - (Query[st[i]] - 1) ) / 2
     96         for(int i = n; i > 0; i--) {
     97             ans[i] = (Query(se[i] - 1) - Query(st[i])) / 2;
     98             Update(se[i], -1);
     99             Update(st[i], -1);
    100         }
    101 
    102         for(int i = 1; i <= n; i++) {
    103             printf("%d", ans[i]);
    104             if( i == n ) printf("
    ");
    105             else printf(" ");
    106         }
    107     }
    108     return 0;
    109 }
    View Code

    我根据上题的代码也写了一份POJ 3321的代码,顺利AC了之后,看了看别人的代码,发现自己处理的有点复杂 (就是MDZZ)。
    先上一份看了别人之后修改过的DFS的代码
    1 void dfs(int u, int fa)
    2 {
    3     st[u] = ++cnt;
    4     for(int k = head[u]; ~k; k = edge[k].nxt){
    5         int v = edge[k].v;
    6         if( v != fa ) dfs(v, u);
    7     }
    8     ed[u] = cnt;
    9 }
    其实完全可以抛弃上一题的que数组,直接用这样的方式来处理st和ed数组。
    虽然我觉得用que数组的话真的很好理解,但是变得比较冗杂了。
    我们还是举HDU 3887的例子(谁让POJ 3321这个样例太不好举例了。。)
    我们这样处理的话就是直接去掉我上面的重复的数字,变成:
    node:7 1 3 15 12 4 10 14 2 13 9 11 6 5 8  
    st和ed两个数组对应的下标分别是:
    st: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    ed:15 2 5 4 5 6 10 10 9 10 15 12 15 14 15 (对不齐,将就看看吧= =)
    我们直接根据这样就可以建立一个树状数组了。
    例如节点7的领域:【1,15】,
      节点1的领域:【2,2】,
      以此类推。
    然后因为我们的树状数组变了,所以我们的询问和更新也肯定变了。
    询问还是  【 st[node] - 1 ,ed[node] 】,只不过区间的值变小了,因为没有重复,我们不用对答案除以2了。
    更新的区间就只要更新st[node]了,因为看上面,st[node]代表的是当下标取node时对应于该节点的左端点,所以只要更新st[node]就可以了。
    还有这题可能卡了vector,我用的是前向星,一开始用vector超时了。
    下面给出代码
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <algorithm>
      5 using namespace std;
      6 #define N 100005
      7 struct node
      8 {
      9     int v, nxt;
     10 }edge[N*2];
     11 int bit[N], st[N], ed[N], head[N], mark[N], cnt, tot, n;
     12 
     13 void add(int u,int v)
     14 {
     15     edge[tot].v = v;
     16     edge[tot].nxt = head[u];
     17     head[u] = tot++;
     18     edge[tot].v = u;
     19     edge[tot].nxt = head[v];
     20     head[v] = tot++;
     21 }
     22 
     23 int lowbit(int x)
     24 {
     25     return x & (-x);
     26 }
     27 
     28 int Query(int x)
     29 {
     30     int ans = 0;
     31     while( x > 0 ){
     32         ans += bit[x];
     33         x -= lowbit(x);
     34     }
     35     return ans;
     36 }
     37 
     38 void Update(int x, int value)
     39 {
     40     while( x <= n ){
     41         bit[x] += value;
     42         x += lowbit(x);
     43     }
     44 }
     45 
     46 void dfs(int u, int fa)
     47 {
     48     st[u] = ++cnt;
     49     for(int k = head[u]; ~k; k = edge[k].nxt){
     50         int v = edge[k].v;
     51         if( v != fa ) dfs(v, u);
     52     }
     53     ed[u] = cnt;
     54 }
     55 
     56 int main()
     57 {
     58     tot = 0, cnt = 0;
     59     memset(bit, 0, sizeof(bit));
     60     memset(head, -1, sizeof(head));
     61     scanf("%d", &n);
     62     for(int i = 1; i < n; i++){
     63         int u, v;
     64         scanf("%d%d", &u, &v);
     65         add(u, v);
     66     }
     67     for(int i = 1; i <= n; i++){
     68         Update(i, 1);
     69         mark[i] = 1;
     70     }
     71 
     72     dfs(1, -1);
     73 
     74     int q;
     75     scanf("%d", &q);
     76     while(q--){
     77         char s[3];
     78         int node;
     79         scanf("%s%d", s, &node);
     80         if(s[0] == 'Q'){
     81             int ans = Query(ed[node]) - Query(st[node] - 1);
     82             printf("%d
    ", ans);
     83         }
     84         else{
     85             mark[node] *= -1;
     86             Update(st[node], mark[node]);
     87         }
     88         printf("%d  %d
    ", bit[st[1]], bit[ed[1]]);
     89     }
     90     return 0;
     91 }
     92 //15
     93 //1 10
     94 //1 7
     95 //1 9
     96 //1 3
     97 //1 4
     98 //10 14
     99 //14 2
    100 //14 13
    101 //9 11
    102 //9 6
    103 //6 5
    104 //6 8
    105 //3 15
    106 //3 12
    107 //8
    108 //Q 1
    109 //C 1
    110 //C 3
    111 //C 5
    112 //Q 1
    113 //C 1
    114 //Q 1
    115 //Q 5
     
  • 相关阅读:
    掌握 ActionResult
    EF 的 霸气配置
    MVC 3 数据验证 Model Validation 详解
    Entity Framework 插入数据 解决主键非自增问题
    线程池(C#)
    socket 基础学习
    oracle创建job方法
    C# 任意类型数据转JSON格式
    JDBC(连接数据库的四个主要步骤)
    oracle 存储过程详细介绍(创建,删除存储过程,参数传递等)
  • 原文地址:https://www.cnblogs.com/fightfordream/p/5682549.html
Copyright © 2011-2022 走看看