dfs序 题目小集
来源:互联网 发布:淘宝卷和商品连在一起 编辑:程序博客网 时间:2024/05/16 02:54
参考
dfs序题目练习 ——樱花庄的龙之介大人
dfs序专题学习 ——Miracle_ma
HDU 5692 +线段树
题意
给定一棵树,有两种操作:
1. 改变某个点
2. 定义路径的价值为其上所有点的权值之和,询问以
分析
(画好了图上传不了就很气)
1 /\ 2 3 /\4 5
对于这样的一棵树,
就上图而论,
将原树映射到一棵线段树上,线段树的线段为
而对点
这么好用的嘛!
是的,我们考虑题目的要求:改变某个点
更改点
希望讲清楚了
Code
#pragma comment(linker, "/STACK:1024000000,1024000000")#include <bits/stdc++.h>#define lson (rt << 1)#define rson (rt << 1 | 1)#define maxn 100010typedef long long LL;int le[maxn], ri[maxn], ne[maxn], tot, cnt, kas;LL val[maxn], p[maxn], a[maxn];struct node { int l, r; LL val, tag;}tr[maxn * 4];struct Edge { int to, ne; Edge(int a = 0, int b = 0): to(a), ne(b) {}}edge[maxn * 2];void add(int u, int v) { edge[tot] = Edge(v, ne[u]); ne[u] = tot++;}void init() { tot = cnt = 0; memset(ne, -1, sizeof(ne));}inline LL max(LL a, LL b) { return a > b ? a : b; }inline int midi(int l, int r) { return l + r >> 1; }inline void push_up(int rt) { tr[rt].val = max(tr[lson].val, tr[rson].val); }inline void push_down(int rt) { if (tr[rt].tag) { tr[lson].tag += tr[rt].tag; tr[rson].tag += tr[rt].tag; tr[lson].val += tr[rt].tag; tr[rson].val += tr[rt].tag; tr[rt].tag = 0; }}void build(int rt, int l, int r) { tr[rt].l = l; tr[rt].r = r; tr[rt].tag = 0; if (l == r) { tr[rt].val = a[l]; return; } int mid = midi(l, r); build(lson, l, mid); build(rson, mid + 1, r); push_up(rt);}void dfs(int u, int fa, LL w) { le[u] = ri[u] = ++cnt; p[u] = w; for (int i = ne[u]; i != -1; i = edge[i].ne) { int v = edge[i].to; if (v == fa) continue; dfs(v, u, w + val[v]); ri[u] = max(ri[u], ri[v]); }}void modify(int rt, int l, int r, LL add) { if (tr[rt].l == l && tr[rt].r == r) { tr[rt].tag += add; tr[rt].val += add; return; } push_down(rt); int mid = midi(tr[rt].l, tr[rt].r); if (r <= mid) modify(lson, l, r, add); else if (l > mid) modify(rson, l, r, add); else { modify(lson, l, mid, add); modify(rson, mid + 1, r, add); } push_up(rt);}LL query(int rt, int l, int r) { if (tr[rt].l == l && tr[rt].r == r) return tr[rt].val; push_down(rt); int mid = midi(tr[rt].l, tr[rt].r); if (r <= mid) return query(lson, l, r); else if (l > mid) return query(rson, l, r); else return max(query(lson, l, mid), query(rson, mid + 1, r));}void work() { printf("Case #%d:\n", ++kas); init(); int n, m; scanf("%d%d", &n, &m); for (int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); } for (int i = 0; i < n; ++i) scanf("%lld", &val[i]); dfs(0, -1, val[0]); for (int i = 0; i < n; ++i) a[le[i]] = p[i]; build(1, 1, n); while (m--) { int x, u; LL w; scanf("%d", &x); if (x == 0) { scanf("%d%lld", &u, &w); modify(1, le[u], ri[u], w - val[u]); val[u] = w; } else { scanf("%d", &u); printf("%lld\n", query(1, le[u], ri[u])); } }}int main() { freopen("in.txt", "r", stdin); int T; scanf("%d", &T); while (T--) work(); return 0;}
POJ 3321 +树状数组
麻烦移步本菜另一篇博文 poj 3321 Apple Tree 树状数组 dfs序
HDU 5468 +莫比乌斯反演
题意
给定一棵树,每个节点都有一个权值。对于每一个节点,问以它为根的子树中的点与它的权值互质的有多少个。
参考
AOQNRMGYXLMV 的博客
分析
即问
即
用
Code
#include <bits/stdc++.h>#include <vector>#define maxn 100000#define maxm maxn + 10using namespace std;int mu[maxm], prime[maxm], cnt[maxm], kas, ans[maxm], ne[maxm], tot, val[maxm];bool check[maxm];vector<int> fac[maxm];struct Edge { int to, ne; Edge(int a = 0, int b = 0) : to(a), ne(b) {}}edge[maxn * 2];void add(int u, int v) { edge[tot] = Edge(v, ne[u]); ne[u] = tot++;}void init() { int tot = 0; mu[1] = 1; for (int i = 1; i <= maxn; ++i) fac[i].push_back(1); for (int i = 2; i <= maxn; ++i) { if (!check[i]) { prime[tot++] = i; mu[i] = -1; } for (int j = 0; j < tot; ++j) { if (i * prime[j] > maxn) break; check[i * prime[j]] = true; if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } mu[i * prime[j]] = -mu[i]; } if (mu[i] != 0) { for (int j = i; j <= maxn; j += i) fac[j].push_back(i); } }}void dfs(int u, int fa) { vector<int> pre; ans[u] = 0; for (auto x : fac[val[u]]) { pre.push_back(cnt[x]); ++cnt[x]; } for (int i = ne[u]; ~i; i = edge[i].ne) { int v = edge[i].to; if (v == fa) continue; dfs(v, u); } vector<int>& ve = fac[val[u]]; int sz = ve.size(); for (int i = 0; i < sz; ++i) { ans[u] += mu[ve[i]] * (cnt[ve[i]] - pre[i]); }}int n;void work() { memset(cnt, 0, sizeof(cnt)); memset(ne, -1, sizeof(ne)); tot = 0; for (int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); } for (int i = 1; i <= n; ++i) scanf("%d", &val[i]); dfs(1, -1); printf("Case #%d: %d", ++kas, ans[1]); for (int i = 2; i <= n; ++i) printf(" %d", ans[i]); printf("\n");}int main() { freopen("in.txt", "r", stdin); init(); while (scanf("%d", &n) != EOF) work(); return 0;}
HDU 3887 +树状数组
题意
给定一棵树,对每个节点
思路
求得
(哇这种从大到小查询啦从小到大插入啦的思想真的炒鸡重要
Code
#include <bits/stdc++.h>#define maxn 100010using namespace std;struct Edge { int to, ne; Edge(int a = 0, int b = 0) : to(a), ne(b) {}}edge[maxn * 2];int ans[maxn], le[maxn], ri[maxn], c[maxn], cnt, tot, ne[maxn];void addEdge(int u, int v) { edge[tot] = Edge(v, ne[u]); ne[u] = tot++;}void dfs(int u, int fa) { le[u] = ri[u] = ++cnt; for (int i = ne[u]; ~i; i = edge[i].ne) { int v = edge[i].to; if (v == fa) continue; dfs(v, u); ri[u] = max(ri[u], ri[v]); }}int n, p;inline int lowbit(int x) { return x & (-x); }inline void add(int x, int del) { while (x <= n) c[x] += del, x += lowbit(x); }inline int query(int x) { int ret = 0; while (x) ret += c[x], x -= lowbit(x); return ret; }void work() { tot = cnt = 0; memset(ne, -1, sizeof(ne)); memset(c, 0, sizeof(c)); for (int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); addEdge(u, v); addEdge(v, u); } dfs(p, -1); for (int i = 1; i <= n; ++i) add(i, 1); for (int i = n; i >= 1; --i) { ans[i] = query(ri[i]) - query(le[i]); add(le[i], -1); } printf("%d", ans[1]); for (int i = 2; i <= n; ++i) printf(" %d", ans[i]); printf("\n");}int main() { while (scanf("%d%d", &n, &p) != EOF && n + p) work(); return 0;}
update-2017.9.5
今天写 HDU 5877 Weak Pair dfs序 + 树状数组 + 离散化 时又回来看了看这里,觉得当时怕不是智障了...
就和上面那个莫比乌斯的题一样,进去的时候算一次,出来的时候算一次,就解决了啊0.0
当时愣是不会做去百度然后看到 从大到小查完一个扔一个 的思路觉得棒呆了…(虽然的确是很重要的思想),但这道题本身是很直白很简单的思路…
于是又写了一发
Code
#include <bits/stdc++.h>#define maxn 100010int c[maxn], ans[maxn], n, p, ne[maxn], tot;struct Edge { int to, ne; Edge(int a = 0, int b = 0) : to(a), ne(b) {}}edge[maxn * 2];void addEdge(int u, int v) { edge[tot] = Edge(v, ne[u]); ne[u] = tot++;}int lowbit(int x) { return x & -x; }void add(int x, int d) { while (x <= n) c[x] += d, x += lowbit(x); }int query(int x) { int ret = 0; while (x) ret += c[x], x -= lowbit(x); return ret; }void dfs(int u, int fa) { add(u, 1); int temp = query(u); for (int i = ne[u]; ~i; i = edge[i].ne) { int v = edge[i].to; if (v == fa) continue; dfs(v, u); } ans[u] = query(u) - temp;}void work() { tot = 0; memset(c, 0, sizeof c); memset(ne, -1, sizeof ne); for (int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); addEdge(u, v); addEdge(v, u); } dfs(p, -1); printf("%d", ans[1]); for (int i = 2; i <= n; ++i) printf(" %d", ans[i]); printf("\n");}int main() { while (scanf("%d%d", &n, &p) != EOF && n + p) work(); return 0;}
CF 620E +线段树+bitmasks
题意
给定一棵树,每个节点都有涂有一种颜色(颜色总数
1. 将以
2. 询问以
思路
十分裸的
(这种涂色问颜色数的本菜之前也在 线段树 lazy tag 小合集 -POJ2777写到过,虽然这次和当年(雾)做法并不一样)
这次看了
一个注意点:左移时要用 1LL << c
Code
#include <bits/stdc++.h>#define maxn 400010#define lson (rt << 1)#define rson (rt << 1 | 1)using namespace std;typedef long long LL;int col[maxn], c[maxn], le[maxn], ri[maxn], tot, cnt, ne[maxn];struct Edge { int to, ne; Edge(int a = 0, int b = 0): to(a), ne(b) {}}edge[maxn * 2];struct node { int l, r; LL tag, mask;}tr[maxn * 4];inline int midi(int l, int r) { return l + r >> 1; }void add(int u, int v) { edge[tot] = Edge(v, ne[u]); ne[u] = tot++;}void dfs(int u, int fa) { le[u] = ri[u] = ++cnt; for (int i = ne[u]; ~i; i = edge[i].ne) { int v = edge[i].to; if (v == fa) continue; dfs(v, u); ri[u] = max(ri[u], ri[v]); }}inline void push_up(int rt) { tr[rt].mask = tr[lson].mask | tr[rson].mask;}inline void push_down(int rt) { if (tr[rt].tag) { tr[lson].mask = tr[rson].mask = tr[lson].tag = tr[rson].tag = tr[rt].tag; tr[rt].tag = 0; }}int count(LL x) { int ret = 0; while (x) { ++ret; x &= (x - 1); } return ret;}void build(int rt, int l, int r) { tr[rt].l = l, tr[rt].r = r, tr[rt].tag = 0; if (l == r) { tr[rt].mask = (1LL << c[l]); return; } push_up(rt); int mid = midi(l, r); build(lson, l, mid); build(rson, mid +1, r); push_up(rt);}void modify(int rt, int l, int r, int c) { if (tr[rt].l == l && tr[rt].r == r) { tr[rt].mask = (1LL << c); tr[rt].tag = (1LL << c); return; } push_down(rt); int mid = midi(tr[rt].l, tr[rt].r); if (r <= mid) modify(lson, l, r, c); else if (l > mid) modify(rson, l, r, c); else { modify(lson, l, mid, c); modify(rson, mid + 1, r, c); } push_up(rt);}LL query(int rt, int l, int r) { if (count(tr[rt].mask) == 1) return tr[rt].mask; if (tr[rt].l == l && tr[rt].r == r) return tr[rt].mask; push_down(rt); int mid = midi(tr[rt].l, tr[rt].r); if (r <= mid) return query(lson, l, r); else if (l > mid) return query(rson, l, r); else return query(lson, l, mid) | query(rson, mid + 1, r); push_up(rt);}int n, m;void work() { tot = cnt = 0; memset(ne, -1, sizeof(ne)); for (int i = 1; i <= n; ++i) scanf("%d", &col[i]); for (int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); } dfs(1, -1); for (int i = 1; i <= n; ++i) c[le[i]] = col[i] - 1; build(1, 1, n); while (m--) { int t, v, c; scanf("%d", &t); if (t == 1) { scanf("%d%d", &v, &c); modify(1, le[v], ri[v], c - 1); } else { scanf("%d", &v); printf("%d\n", count(query(1, le[v], ri[v]))); } }}int main() { while (scanf("%d%d", &n, &m) != EOF) work(); return 0;}
- dfs序 题目小集
- DFS题目
- hdu1584 dfs的题目
- 一道dfs题目
- DFS、BFS搜索+题目
- dfs简单题目
- DFS解决组合题目
- POJ 题目 Hopscotch(dfs)
- 简单题目的dfs模版
- DFS算法有趣小题目
- 学校oj题目一(dfs)
- 【线段树+dfs序 模板】hdu 5692 ,百毒之星A 题目 snacks dfs 序 +线段树维护最大值
- 小集合
- 转载小集
- 转载小集
- 开心辞典小集
- 笑话小集
- [省选前题目整理][BZOJ 2588][SPOJ COT]Count On a Tree(DFS序主席树)
- 11. Container With Most Water
- 使用go语言net/http开发一个简单的get/post 接口
- 《数据结构(C语言版)》- 树和二叉树
- 以太坊研究课题
- hdu 1251 统计难题(字典树+空行输入)
- dfs序 题目小集
- 详解:路由器性能的各项指标
- Spring Bean生命周期详解
- 图-强连通模板
- 12. Integer to Roman
- 选择排序
- vscode 配置unity的lua
- html表单的练习
- 我从哪里来,到哪里去-人体奥秘Inside the Human Body