poj-3321-dfs序-线段树-邻接表

思路:用邻接表存图,卡vector【这里被卡哭了QAQ】,用dfs遍历的顺序重新给节点编号,遍历时记录儿子数目。用dfs序建立线段树,change的时候单点更新,查询某子树上的苹果树即是查询该节点[i, i+childnum]这个区间的苹果数目,i指dfs序。

总结:邻接表出边入边傻傻搞不清楚QAQ

AC代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <cstring>
  5 #include <algorithm>
  6 using namespace std;
  7 #define maxn 200010
  8 #define lson l, m, rt<<1
  9 #define rson m+1, r, rt<<1|1
 10 struct node
 11 {
 12     int cnt, val, num;
 13 };
 14 int n, m;
 15 node arr[maxn];
 16 int u[maxn], v[maxn], next[maxn], first[maxn];
 17 bool vis[maxn];
 18 int sgt[maxn<<2];
 19 void init()
 20 {
 21     memset(vis, 0, sizeof(vis));
 22     for(int i = 0; i < n+10; i++)  first[i] = -1;
 23     int e = 0, i;
 24     for(i = 1; i < n; i++) {
 25         scanf("%d%d", &u[i], &v[i]);
 26         next[i] = first[u[i]];
 27         first[u[i]] = i;
 28         u[n-1+i] = v[i];
 29         v[n-1+i] = u[i];
 30         next[n-1+i] = first[u[n-1+i]];
 31         first[u[n-1+i]] = n-1+i;
 32     }
 33 }
 34 int dfs(int i, int &num)
 35 {//cout<<i<<" - "<<num<<endl;
 36     arr[i].val = 1;
 37     arr[i].cnt = 0;
 38     arr[i].num = num;
 39     vis[i] = 1;
 40     for(int j = first[i]; j != -1; j = next[j]) {
 41         if(!vis[v[j]]) { num++; arr[i].cnt += dfs(v[j], num);  }
 42     }
 43     return arr[i].cnt+1;
 44 }
 45 void push_up(int rt)
 46 {
 47     sgt[rt] = sgt[rt<<1] + sgt[rt<<1|1];
 48 }
 49 void build(int l, int r, int rt)
 50 {
 51     sgt[rt] = 1;
 52     if(l == r) return;
 53     int m = (r+l)>>1;
 54     build(lson);
 55     build(rson);
 56     push_up(rt);
 57 }
 58 void change(int l, int r, int rt, int pos)
 59 {
 60     if(l == r) {
 61         if(sgt[rt] == 1) sgt[rt] = 0;
 62         else sgt[rt] = 1;
 63         return;
 64     }
 65     int m = (r+l)>>1;
 66     if(pos <= m) change(lson, pos);
 67     else change(rson, pos);
 68     push_up(rt);
 69 }
 70 int query(int l, int r, int rt, int L, int R )
 71 {
 72     if(L <= l && r <= R) {
 73         return sgt[rt];
 74     }
 75     int res = 0;
 76     int m = (l+r)>>1;
 77     if(L <= m) res += query(lson, L, R);
 78     if(m < R) res += query(rson, L, R);
 79     return res;
 80 }
 81 void work()
 82 {
 83     if(n == 1) {
 84         int x = 1;
 85         scanf("%d", &m);
 86         char re; int k;
 87         while (m--) {
 88             getchar();
 89             scanf("%c%d", &re, &k);
 90             if(re == ‘Q‘) {
 91                 printf("%d\n", x);
 92             }
 93             else {
 94                 if(x == 0) x = 1; else x = 0;
 95             }
 96         }
 97     }else {
 98         init();
 99         int xxx = 1;
100         dfs(1,xxx);
101         build(1, n, 1);
102         char re; int k;
103         scanf("%d", &m);
104         for (int i = 0; i < m; i++) {
105             getchar();
106             scanf("%c%d", &re, &k);
107             if(re == ‘C‘) {
108                 change(1, n, 1, arr[k].num);
109             }
110             else {
111                 int res = query(1, n, 1, arr[k].num, arr[k].num+arr[k].cnt);
112                 printf("%d\n", res);
113             }
114         }
115     }
116 }
117 int main()
118 {
119     while(scanf("%d", &n) != EOF && n) work();
120     return 0;
121 }
122 /*
123 7
124 1 3
125 1 4
126 3 5
127 3 6
128 4 2
129 4 7
130 11
131 Q 2
132 Q 2
133 Q 1
134 C 3
135 Q 3
136 C 3
137 Q 3
138 C 4
139 Q 7
140 Q 4
141 Q 2
142
143 */

时间: 2024-10-16 19:04:43

poj-3321-dfs序-线段树-邻接表的相关文章

POJ 3321 DFS序+线段树

单点修改树中某个节点,查询子树的性质.DFS序 子树序列一定在父节点的DFS序列之内,所以可以用线段树维护. 1: /* 2: DFS序 +线段树 3: */ 4:   5: #include <cstdio> 6: #include <cstring> 7: #include <cctype> 8: #include <algorithm> 9: #include <vector> 10: #include <iostream> 1

codevs1228 (dfs序+线段树)

总结: 第一次遇到dfs序的问题,对于一颗树,记录节点 i 开始搜索的序号 Left[i] 和结束搜索的序号 Righti[i],那么序号在 Left[i] ~ Right[i] 之间的都是节点 i 子树上的节点. 并且此序号与线段树中 L~R 区间对应,在纸上模拟了几遍确实如此,但暂时还未理解为何对应. 此题就是dfs序+线段树的裸题 代码: #include<iostream> #include<vector> #include<cstring> #include&

[BZOJ 3306]树(dfs序+线段树+倍增)

Description 给定一棵大小为 n 的有根点权树,支持以下操作: • 换根 • 修改点权 • 查询子树最小值 Solution 单点修改子树查询的话可以想到用dfs序+线段树来处理,换根的处理画一画图应该可以明白: 如果查询的x是当前的根rt,直接返回整棵树的min 如果rt在x的子树中,用倍增的方法找到离x最近的rt的祖先t,整棵树除t的子树以外的部分就是x当前根下的子树 如果rt不在x的子树中,查询x原来的子树的min值 #include<iostream> #include<

Educational Codeforces Round 6 E dfs序+线段树

题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili上电子科技大学发的视频学习的 将一颗树通过dfs编号的方式 使每个点的子树的编号连在一起作为相连的区间 就可以配合线段树搞子树 因为以前好像听说过 线段树可以解决一种区间修改和查询区间中不同的xx个数...所以一下子就想到了... 但是我不会写线段树..只会最简单的单点修改区间查询...不会用延迟标

【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线)

【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\),问你答案是多少. \(n\leq {10}^5,k\leq {10}^9\) 题解 设\(l\)为这棵树的叶子个数,显然当\(k>\)树的深度时答案都是\(l\). 下面要证明:答案是\(O(l+\frac{n-l}{k})\)的. 我们从下往上贪心,每次选择一个未被覆盖的深度最深的点,覆盖这个点网

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

题目链接 这道题主要是要考虑到同一棵子树中dfs序是连续的 然后我就直接上树剖了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]

Manthan, Codefest 16(G. Yash And Trees(dfs序+线段树))

题目链接:点击打开链接 题意:给你一棵树, 根结点为1, q组操作, 每组操作有两种, 一种是对一个结点的所有子树结点的值全部+1, 另一种是查询一个结点的子树结点上值%m的余数为素数的个数. 思路:对于第一个操作, 我们可以想到用dfs序给树重新标号, 使得一个结点的子树结点为相邻的一条线段, 这样,就可以很容易的用线段树进行处理了.  对于第二个操作, 为了维护一个区间内的值, 我们可以用bitset作为结点信息.  我们可以开一个m位的bitset, 对于每个位, 1表示这个数在此区间中,

CodeForces 838B - Diverging Directions - [DFS序+线段树]

题目链接:http://codeforces.com/problemset/problem/838/B You are given a directed weighted graph with n nodes and 2n?-?2 edges. The nodes are labeled from 1 to n, while the edges are labeled from 1 to 2n?-?2. The graph's edges can be split into two parts.