网上特别讲DFS序的东西好像很少

太简单了? 实用性不大?

看了论文中 7个经典问题, 觉得挺有用的

原文

"所谓DFS序, 就是DFS整棵树依次访问到的结点组成的序列"

"DFS序有一个很强的性质: 一颗子树的所有节点在DFS序内是连续的一段, 利用这个性质我们可以解决很多问题"

基本代码 :

void Dfs(int u, int fa, int dep)
{
seq[++cnt] = u;
st[u] = cnt;
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) {
Dfs(v, u, dep+);
}
}
seq[++cnt] = u;
ed[u] = cnt;
}

关于原文中列出的7个经典问题, 分别实现一下

给定一颗树, 和每个节点的权值

1. 对某个节点X权值加上一个数W, 查询某个子树X里所有点权的和

解 :

由于X子树在DFS序中是连续的一段, 只需要维护一个序列,

支持单点修改和区间查询, 用树状数组就能实现

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; const int MAXN = 1e5+; vector<int> edge[MAXN];
int s[*MAXN];
int seq[*MAXN];
int st[MAXN];
int ed[MAXN];
int cnt; int Lowbit(int x)
{
return x & (-x);
} void Add(int x, int val, int n)
{
for(int i = x; i <= n; i += Lowbit(i)) {
s[i] += val;
}
} int Sum(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s[i];
}
return res;
} void Dfs(int u, int fa)
{
seq[++cnt] = u;
st[u] = cnt;
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) {
Dfs(v, u);
}
}
seq[++cnt] = u;
ed[u] = cnt;
} void Init(int n)
{
for(int i = ; i <= n; i++) {
edge[i].clear();
}
memset(s, , sizeof(s));
} int main()
{
int n, op;
int u, v, w;
int cmd; while(scanf("%d %d", &n, &op) != EOF) {
Init(n);
for(int i = ; i < n-; i++) {
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
cnt = ;
Dfs(, -);
while(op--) {
scanf("%d", &cmd);
if(cmd == ) {
scanf("%d %d", &u, &w);
Add(st[u], w, cnt);
}
else if(cmd == ) {
scanf("%d", &u);
printf("%d\n", Sum(ed[u]) - Sum(st[u] - ));
}
}
} return ;
}

2. 对节点X到Y的最短路上所有点权都加一个数W, 查询某个点的权值

解 :

这个操作等价于

a. 对X到根节点路径上所有点权加W

b. 对Y到根节点路径上所有点权加W

c. 对LCA(x, y)到根节点路径上所有点权值减W

d. 对LCA(x,y)的父节点 parent(LCA(x, y))到根节点路径上所有权值减W

于是要进行四次这样从一个点到根节点的区间修改

将问题进一步简化, 进行一个点X到根节点的区间修改, 查询其他一点Y时

只有X在Y的子树内, X对Y的值才有贡献且贡献值为W

于是只需要更新四个点, 查询一个点的子树内所有点权的和即可

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; const int MAXN = 1e5+; vector<int> edge[MAXN];
int s[*MAXN];
int seq[*MAXN];
int seq1[*MAXN];
int depth[*MAXN];
int first[MAXN];
int dp[*MAXN][];
int st[MAXN];
int ed[MAXN];
int parent[MAXN];
int cnt, num; int Lowbit(int x)
{
return x & (-x);
} void Add(int x, int val, int n)
{
if(x <= ) return;
for(int i = x; i <= n; i += Lowbit(i)) {
s[i] += val;
}
} int Sum(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s[i];
}
return res;
} void Dfs(int u, int fa, int dep)
{
parent[u] = fa;
seq[++cnt] = u;
seq1[++num] = u;
first[u] = num;
depth[num] = dep;
st[u] = cnt;
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) {
Dfs(v, u, dep+);
seq1[++num] = u;
depth[num] = dep;
}
}
seq[++cnt] = u;
ed[u] = cnt;
} void RMQ_Init(int n)
{
for(int i = ; i <= n; i++) {
dp[i][] = i;
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i + ( << j) - <= n; i++) {
int a = dp[i][j-], b = dp[i + ( << (j-))][j-];
dp[i][j] = depth[a] < depth[b] ? a : b;
}
}
} int RMQ_Query(int l, int r)
{
int k = ;
while(( << (k + )) <= r - l + ) k++;
int a = dp[l][k], b = dp[r-(<<k)+][k];
return depth[a] < depth[b] ? a : b;
} int LCA(int u, int v)
{
int a = first[u], b = first[v];
if(a > b) a ^= b, b ^= a, a ^= b;
int res = RMQ_Query(a, b);
return seq1[res];
} void Init(int n)
{
for(int i = ; i <= n; i++) {
edge[i].clear();
}
memset(s, , sizeof(s));
} int main()
{
int n, op;
int u, v, w;
int cmd; while(scanf("%d %d", &n, &op) != EOF) {
Init(n);
for(int i = ; i < n-; i++) {
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
cnt = , num = ;
Dfs(, -, );
RMQ_Init(num);
while(op--) {
scanf("%d", &cmd);
if(cmd == ) {
scanf("%d %d %d", &u, &v, &w);
int lca = LCA(u, v);
Add(st[u], w, cnt);
Add(st[v], w, cnt);
Add(lca, -w, cnt);
Add(parent[lca], -w, cnt);
}
else if(cmd == ) {
scanf("%d", &u);
printf("%d\n", Sum(ed[u]) - Sum(st[u] - ));
}
}
} return ;
}

3. 对节点X到Y的最短路上所有点权都加一个数W, 查询某个点子树的权值之和

解 :

同问题2中的修改方法, 转化为修改某点到根节点的权值加/减W

当修改某个节点A, 查询另一节点B时

只有A在B的子树内, Y的值会增加 W * (depth[A] - depth[B] + 1) == W * (depth[A] + 1) - W * depth[B]

同样是用树状数组来查询Y的子树, 修改 和 查询方法都要新增一个数组

第一个数组保存 W * (depth[A] + 1), 第二个数组保存 W

每次查询结果为Sum(ed[B]) - Sum(st[B]-1) - (Sum1(ed[B]) - Sum(st[B]-1)) * depth[B]

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; const int MAXN = 1e5+; vector<int> edge[MAXN];
int s[*MAXN];
int s1[*MAXN];
int seq[*MAXN];
int seq1[*MAXN];
int depth[*MAXN];
int first[MAXN];
int dp[*MAXN][];
int st[MAXN];
int ed[MAXN];
int parent[MAXN];
int cnt, num; int Lowbit(int x)
{
return x & (-x);
} void Add(int x, int val, int n)
{
if(x <= ) return;
for(int i = x; i <= n; i += Lowbit(i)) {
s[i] += val;
}
} void Add1(int x, int val, int n)
{
if(x <= ) return;
for(int i = x; i <= n; i += Lowbit(i)) {
s1[i] += val;
}
} int Sum(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s[i];
}
return res;
} int Sum1(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s1[i];
}
return res;
} void Dfs(int u, int fa, int dep)
{
parent[u] = fa;
seq[++cnt] = u;
seq1[++num] = u;
first[u] = num;
depth[num] = dep;
st[u] = cnt;
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) {
Dfs(v, u, dep+);
seq1[++num] = u;
depth[num] = dep;
}
}
seq[++cnt] = u;
ed[u] = cnt;
} void RMQ_Init(int n)
{
for(int i = ; i <= n; i++) {
dp[i][] = i;
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i + ( << j) - <= n; i++) {
int a = dp[i][j-], b = dp[i + ( << (j-))][j-];
dp[i][j] = depth[a] < depth[b] ? a : b;
}
}
} int RMQ_Query(int l, int r)
{
int k = ;
while(( << (k + )) <= r - l + ) k++;
int a = dp[l][k], b = dp[r-(<<k)+][k];
return depth[a] < depth[b] ? a : b;
} int LCA(int u, int v)
{
int a = first[u], b = first[v];
if(a > b) a ^= b, b ^= a, a ^= b;
int res = RMQ_Query(a, b);
return seq1[res];
} void Init(int n)
{
for(int i = ; i <= n; i++) {
edge[i].clear();
}
memset(s, , sizeof(s));
} int main()
{
int n, op;
int u, v, w;
int cmd; while(scanf("%d %d", &n, &op) != EOF) {
Init(n);
for(int i = ; i < n-; i++) {
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
cnt = , num = ;
Dfs(, -, );
RMQ_Init(num);
while(op--) {
scanf("%d", &cmd);
if(cmd == ) {
scanf("%d %d %d", &u, &v, &w);
int lca = LCA(u, v);
Add(st[u], w * depth[first[u]] + w, cnt);
Add1(st[u], w, cnt);
Add(st[v], w * depth[first[v]] + w, cnt);
Add1(st[v], w, cnt);
Add(lca, -(w * depth[first[lca]] + w), cnt);
Add1(lca, -w, cnt);
Add(parent[lca], -(w * depth[first[parent[lca]]] + w), cnt);
Add1(parent[lca], -w, cnt);
}
else if(cmd == ) {
scanf("%d", &u);
printf("%d\n", Sum(ed[u]) - Sum(st[u] - ) - \
depth[first[u]] * (Sum1(ed[u]) - Sum1(st[u] - )));
}
}
} return ;
}

4. 对某个点X权值加上一个数W, 查询X到Y路径上所有点权之和

解 :

求X到Y路径上所有的点权之和, 和前面X到Y路径上所有点权加一个数相似

这个问题转化为

X到根节点的和 + Y到根节点的和 - LCA(x, y)到根节点的和 - parent(LCA(x,y)) 到根节点的和

于是只要支持单点修改, 区间查询即可

要注意的是修改, 要在该点开始出现位置加W, 在结束位置减W

这样能保证在该节点子树内的能加到这个W, 不在该点子树内的无影响

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; const int MAXN = 1e5+; vector<int> edge[MAXN];
int s[*MAXN];
int s1[*MAXN];
int seq[*MAXN];
int seq1[*MAXN];
int depth[*MAXN];
int first[MAXN];
int dp[*MAXN][];
int st[MAXN];
int ed[MAXN];
int parent[MAXN];
int cnt, num; int Lowbit(int x)
{
return x & (-x);
} void Add(int x, int val, int n)
{
if(x <= ) return;
for(int i = x; i <= n; i += Lowbit(i)) {
s[i] += val;
}
} int Sum(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s[i];
}
return res;
} void Dfs(int u, int fa, int dep)
{
parent[u] = fa;
seq[++cnt] = u;
seq1[++num] = u;
first[u] = num;
depth[num] = dep;
st[u] = cnt;
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) {
Dfs(v, u, dep+);
seq1[++num] = u;
depth[num] = dep;
}
}
seq[++cnt] = u;
ed[u] = cnt;
} void RMQ_Init(int n)
{
for(int i = ; i <= n; i++) {
dp[i][] = i;
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i + ( << j) - <= n; i++) {
int a = dp[i][j-], b = dp[i + ( << (j-))][j-];
dp[i][j] = depth[a] < depth[b] ? a : b;
}
}
} int RMQ_Query(int l, int r)
{
int k = ;
while(( << (k + )) <= r - l + ) k++;
int a = dp[l][k], b = dp[r-(<<k)+][k];
return depth[a] < depth[b] ? a : b;
} int LCA(int u, int v)
{
int a = first[u], b = first[v];
if(a > b) a ^= b, b ^= a, a ^= b;
int res = RMQ_Query(a, b);
return seq1[res];
} void Init(int n)
{
for(int i = ; i <= n; i++) {
edge[i].clear();
}
memset(s, , sizeof(s));
} int main()
{
int n, op;
int u, v, w;
int cmd; while(scanf("%d %d", &n, &op) != EOF) {
Init(n);
for(int i = ; i < n-; i++) {
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
cnt = , num = ;
Dfs(, -, );
RMQ_Init(num);
while(op--) {
scanf("%d", &cmd);
if(cmd == ) {
scanf("%d %d", &u, &w);
Add(st[u], w, cnt);
Add(ed[u], -w, cnt);
}
else if(cmd == ) {
scanf("%d %d", &u, &v);
int lca = LCA(u, v);
printf("%d\n", Sum(st[u]) + Sum(st[v]) - Sum(st[lca]) - Sum(st[parent[lca]]));
}
}
} return ;
}

5. 对子树X里所有节点加上一个值W, 查询某个点的值

解 :

对DFS序来说, 子树内所有节点加W, 就是一段区间加W

所以这个问题就是 区间修改, 单点查询

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; const int MAXN = 1e5+; vector<int> edge[MAXN];
int s[*MAXN];
int s1[*MAXN];
int seq[*MAXN];
int seq1[*MAXN];
int depth[*MAXN];
int first[MAXN];
int dp[*MAXN][];
int st[MAXN];
int ed[MAXN];
int parent[MAXN];
int cnt, num; int Lowbit(int x)
{
return x & (-x);
} void Add(int x, int val, int n)
{
if(x <= ) return;
for(int i = x; i <= n; i += Lowbit(i)) {
s[i] += val;
}
} int Sum(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s[i];
}
return res;
} void Dfs(int u, int fa)
{
seq[++cnt] = u;
st[u] = cnt;
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) {
Dfs(v, u);
}
}
seq[++cnt] = u;
ed[u] = cnt;
} void Init(int n)
{
for(int i = ; i <= n; i++) {
edge[i].clear();
}
memset(s, , sizeof(s));
} int main()
{
int n, op;
int u, v, w;
int cmd; while(scanf("%d %d", &n, &op) != EOF) {
Init(n);
for(int i = ; i < n-; i++) {
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
cnt = ;
Dfs(, -);
while(op--) {
scanf("%d", &cmd);
if(cmd == ) {
scanf("%d %d", &u, &w);
Add(st[u], w, cnt);
Add(ed[u], -w, cnt);
}
else if(cmd == ) {
scanf("%d", &u);
printf("%d\n", Sum(u));
}
}
} return ;
}

6.对子树X里所有节点加上一个值W, 查询某个子树的权值和

解 :

子树所有节点加W, 就是某段区间加W, 查询某个子树的权值和, 就是查询某段区间的和

区间修改区间求和, 是线段树的经典问题, 用线段树可以很好解决

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; typedef struct {
int l, r, sum, add;
} Seg; const int MAXN = 1e5+; Seg T[*MAXN];
vector<int> edge[MAXN];
int s[*MAXN];
int seq[*MAXN];
int st[MAXN];
int ed[MAXN];
int cnt; void Dfs(int u, int fa)
{
seq[++cnt] = u;
st[u] = cnt;
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) {
Dfs(v, u);
}
}
seq[++cnt] = u;
ed[u] = cnt;
} void Build(int l, int r, int k)
{
T[k].l = l, T[k].r = r, T[k].sum = T[k].add;
if(l == r) return;
int mid = (l + r) >> ;
Build(l, mid, k<<);
Build(mid+, r, k<<|);
} void PushDown(int k)
{
if(T[k].add) {
T[k<<].sum += (T[k<<].r - T[k<<].l + ) * T[k].add;
T[k<<].add += T[k].add;
T[k<<|].sum += (T[k<<|].r - T[k<<|].l + ) * T[k].add;
T[k<<|].add += T[k<<].add;
T[k].add = ;
}
} void PushUp(int k)
{
T[k].sum = T[k<<].sum + T[k<<|].sum;
} void Update(int l, int r, int val, int k)
{
if(T[k].l == l && T[k].r == r) {
T[k].sum += (r - l + ) * val;
T[k].add += val;
return ;
}
PushDown(k);
int mid = (T[k].l + T[k].r) >> ;
if(r <= mid) Update(l, r, val, k<<);
else if(l > mid) Update(l, r, val, k<<|);
else {
Update(l, mid, val, k<<);
Update(mid+, r, val, k<<|);
}
PushUp(k);
} int Query(int l, int r, int k)
{
if(T[k].l == l && T[k].r == r) {
return T[k].sum;
}
PushDown(k);
int mid = (T[k].l + T[k].r) >> ;
if(r <= mid) return Query(l, r, k<<);
else if(l > mid) return Query(l, r, k<<|);
else {
return Query(l, mid, k<<) + Query(mid+, r, k<<|);
}
} void Init(int n)
{
for(int i = ; i <= n; i++) {
edge[i].clear();
}
} int main()
{
int n, op;
int u, v, w;
int cmd; while(scanf("%d %d", &n, &op) != EOF) {
Init(n);
for(int i = ; i < n-; i++) {
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
cnt = ;
Dfs(, -);
Build(, cnt, );
while(op--) {
scanf("%d", &cmd);
if(cmd == ) {
scanf("%d %d", &u, &w);
Update(st[u], ed[u], w, );
}
else if(cmd == ) {
scanf("%d", &u);
printf("%d\n", Query(st[u], ed[u], ) / );
}
}
} return ;
}

7. 对节点X的子树所有节点加上一个值W, 查询X到Y的路径上所有点的权值和

解:

同问题4把路径上求和转化为四个点到根节点的和

X到根节点的和 + Y到根节点的和 - LCA(x, y)到根节点的和 - parent(LCA(x,y)) 到根节点的和

修改一点A, 查询某点B到根节点时, 只有B在A的子树内, A对B才有贡献

贡献为W * (depth[B] - depth[A] + 1) == W * (1 - depth[A]) + W * depth[B]

和第三题一样, 用两个树状数组维护 W *(depth[A] + 1), W * depth[B]

同样要注意修改某点时, 在一点开始位置加, 在其结束位置减

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std; typedef struct {
int l, r, sum, add;
} Seg; const int MAXN = 1e5+; Seg T[*MAXN];
vector<int> edge[MAXN];
int s[*MAXN];
int s1[*MAXN];
int seq[*MAXN];
int seq1[*MAXN];
int depth[*MAXN];
int first[MAXN];
int dp[*MAXN][];
int parent[MAXN];
int st[MAXN];
int ed[MAXN];
int cnt, cnt1; int Lowbit(int x)
{
return x & (-x);
} void Add(int x, int val, int n)
{
if(x <= ) return ;
for(int i = x; i <= n; i += Lowbit(i)) {
s[i] += val;
}
} void Add1(int x, int val, int n)
{
if(x <= ) return ;
for(int i = x; i <= n; i += Lowbit(i)) {
s1[i] += val;
}
} int Sum(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s[i];
}
return res;
} int Sum1(int x)
{
int res = ;
for(int i = x; i > ; i -= Lowbit(i)) {
res += s1[i];
}
return res;
} void RMQ_Init(int n)
{
for(int i = ; i <= n; i++) {
dp[i][] = i;
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i + ( << j) - <= n; i++) {
int a = dp[i][j-], b = dp[i + ( << (j-))][j-];
dp[i][j] = depth[a] < depth[b] ? a : b;
}
}
} int RMQ_Query(int l, int r)
{
int k = ;
while(( << (k + )) <= r - l + ) k++;
int a = dp[l][k], b = dp[r-( << k)+][k];
return depth[a] < depth[b] ? a : b;
} int LCA(int u, int v)
{
int a = first[u], b = first[v];
if(a > b) a ^= b, b ^= a, a ^= b;
int res = RMQ_Query(a, b);
return seq1[res];
} void Dfs(int u, int fa, int dep)
{
seq[++cnt] = u;
seq1[++cnt1] = u;
first[u] = cnt1;
parent[u] = fa;
depth[cnt1] = dep;
st[u] = cnt;
int len = edge[u].size();
for(int i = ; i < len; i++) {
int v = edge[u][i];
if(v != fa) {
Dfs(v, u, dep+);
seq1[++cnt1] = u;
depth[cnt1] = dep;
}
}
seq[++cnt] = u;
ed[u] = cnt;
} void Init(int n)
{
for(int i = ; i <= n; i++) {
edge[i].clear();
}
memset(s, , sizeof(s));
memset(s1, , sizeof(s1));
} void Debug()
{
int u, v;
while() {
scanf("%d %d", &u, &v);
printf("The LCA of %d %d is %d\n", u, v, LCA(u, v));
}
} int main()
{
int n, op;
int u, v, w;
int cmd; while(scanf("%d %d", &n, &op) != EOF) {
Init(n);
for(int i = ; i < n-; i++) {
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
cnt = cnt1 = ;
Dfs(, , );
RMQ_Init(cnt1);
while(op--) {
scanf("%d", &cmd);
if(cmd == ) {
scanf("%d %d", &u, &w);
Add(st[u], w * ( - depth[first[u]]), cnt);
Add(ed[u], -w * ( - depth[first[u]]), cnt);
Add1(st[u], w, cnt);
Add1(ed[u], -w, cnt);
}
else if(cmd == ) {
scanf("%d %d", &u, &v);
int lca = LCA(u, v);
int par = parent[lca];
int ans = Sum(st[u]);
ans += depth[first[u]] * Sum1(st[u]);
ans += Sum(st[v]);
ans += depth[first[v]] * Sum1(st[v]);
ans -= Sum(st[lca]);
ans -= depth[first[lca]] * Sum1(st[lca]);
ans -= Sum(st[par]);
ans -= depth[first[par]] * Sum1(st[par]);
printf("%d\n", ans);
}
}
} return ;
}

DFS序 参考许昊然《数据结构漫谈》的更多相关文章

  1. dfs序七个经典问题

    update-2018.07.23: 原文问题五思路描述有误,已更正. 参考自:<数据结构漫谈>-许昊然 dfs序是树在dfs先序遍历时的序列,将树形结构转化成序列问题处理. dfs有一个 ...

  2. 【转载】dfs序七个经典问题

    作者:weeping 出处:www.cnblogs.com/weeping/ 原文链接 https://www.cnblogs.com/weeping/p/6847112.html 参考自:<数 ...

  3. dfs序七个经典问题(转)

    我这个人不怎么喜欢写轻重链剖分和LCT 还是喜欢dfs序.括号序列之类的 毕竟线段树好写多了 然后就有了这篇转载的文章 写在这边以后有时间看看 原文链接:https://www.cnblogs.com ...

  4. dfs序七个经典问题[转]

    dfs序七个经典问题 参考自:<数据结构漫谈>-许昊然 dfs序是树在dfs先序遍历时的序列,将树形结构转化成序列问题处理. dfs有一个很好的性质:一棵子树所在的位置处于一个连续区间中. ...

  5. SPOJ Query on a tree III (树剖(dfs序)+主席树 || Splay等平衡树)(询问点)

    You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node whose ...

  6. CodeForces 570D DFS序 树状数组 Tree Requests

    参考九野巨巨的博客. 查询一个子树内的信息,可以通过DFS序转成线形的,从而用数据结构来维护. #include <iostream> #include <cstdio> #i ...

  7. BZOJ4034 [HAOI2015]树上操作+DFS序+线段树

    参考:https://www.cnblogs.com/liyinggang/p/5965981.html 题意:是一个数据结构题,树上的,用dfs序,变成线性的: 思路:对于每一个节点x,记录其DFS ...

  8. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

  9. BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序

    BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序 Description 由乃为了吃到最传统最纯净的美食,决定亲自开垦一片菜园.现有一片空地,由乃已经规划n个地点准备种上蔬菜.最新 ...

随机推荐

  1. equals函数的作用

    1.equals函数在什么地方 在Object类中,写法与==一样,但是我们用的时候要重写这个equals方法 String类型中的equals是复写好的 2.equals函数的作用 ==号在比较两个 ...

  2. Android Activity各启动模式的差异

    Activity共有四种启动模式:standard,singleTop,singleTask,singleInstance 为了方便描述和理解,布局文件.Manifest文件和各个java文件如下: ...

  3. iOS UICollectionview的详细介绍

    转载自:http://jinqianchina.github.io/2015/08/16/UICollectionview%E7%9A%84%E4%BD%BF%E7%94%A8%E8%AF%A6%E8 ...

  4. Cocos_Code_Ide学习(一):理解Cocos Lua Project下的frameworks的proj.win32

    第一次写,不知道有没有用,有不对的地方,接受大家的批评.勿喷,谢谢. 1.首先,创建工程 ------------------------------------------------------- ...

  5. js四舍五入的bug和方法

    简单来说js使用原生toFixed(x)截取小数的时候会有误差,出现在比如var o = 0.3303;o.toFixed(3);//0.330 toFixed(x)本来也是一个获取四舍五入的截取方法 ...

  6. 滚动条响应鼠标滑轮事件实现上下滚动的js代码

    <script type="text/javascript"> var scrollFunc=function(e){ e=e || window.event; if( ...

  7. python学习笔记(一)元组,序列,字典

    python学习笔记(一)元组,序列,字典

  8. java导入导出excel常用操作小结及简单示例

    POI中常用设置EXCEL的操作小结: 操作excel如下 HSSFWorkbook wb = new HSSFWorkbook();  //创建一个webbook,对应一个Excel文件 HSSFS ...

  9. 2、MyBatis.NET学习笔记之CodeSmith使用

    说明:本系列随笔会与CSDN同步发布,当然这里先发,因为这里可以用WLW.但刚才由于误操作,没有重新发上来.只好先在CSDN先发了.重往这里发时图片无法处理,索性直接粘过来吧! 使用框架后一些相关的配 ...

  10. unity 基础学习 transform

    unity  基础学习   transform 1.unity采用的是右手坐标系,X轴右手为+,Y轴向上为+,Z轴朝里为+; 但是我们从3D MAX中导入模型之后,发现轴向并没有遵从这个原理, 其实是 ...