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
     
  • 相关阅读:
    PAT 甲级 1027 Colors in Mars
    PAT 甲级 1026 Table Tennis(模拟)
    PAT 甲级 1025 PAT Ranking
    PAT 甲级 1024 Palindromic Number
    PAT 甲级 1023 Have Fun with Numbers
    PAT 甲级 1021 Deepest Root (并查集,树的遍历)
    Java实现 蓝桥杯VIP 算法训练 无权最长链
    Java实现 蓝桥杯VIP 算法训练 无权最长链
    Java实现 蓝桥杯 算法提高 抽卡游戏
    Java实现 蓝桥杯 算法提高 抽卡游戏
  • 原文地址:https://www.cnblogs.com/fightfordream/p/5682549.html
Copyright © 2011-2022 走看看