题目传送门

题意:给你一棵树,树上的每个节点都有树值,给m个查询,问以每个点u为根的子树下有多少种权值恰好出现k次。

分析:首先要对权值离散化,然后要将树形转换为线形,配上图:。然后按照右端点从小到大排序,离线操作:将每一个深度的权值分组到相同权值的cnt中,当sz == k时,用树状数组更新+1,表示在该深度已经存在k个相同的权值,如果>k,之前k个-2(-1是恢复原样,再-1是为下次做准备?),然后一个点的子树的答案就是 sum (r) - sum (l-1)。

当然,区间离线问题用莫队算法是很好做的。

收获:1. 离散化  2. DFS序,树形变线形  3. 离线操作  4. 莫队算法

代码(树状数组):

/************************************************
* Author :Running_Time
* Created Time :2015/9/10 星期四 19:15:22
* File Name :I.cpp
************************************************/ #include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std; #define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
struct Edge {
int v, nex;
}edge[N*2];
struct Query {
int l, r, id;
Query (int _l = 0, int _r = 0, int _id = 0) : l (_l), r (_r), id (_id) {}
bool operator < (const Query &x) const {
return r < x.r;
}
}q[N];
struct BIT {
int c[N];
void init(void) {
memset (c, 0, sizeof (c));
}
void updata(int i, int x) {
while (i < N) {
c[i] += x; i += i & (-i);
}
}
int query(int i) {
int ret = 0;
while (i) {
ret += c[i]; i -= i & (-i);
}
return ret;
}
}bit;
int head[N], dfn[N], low[N], w[N], p[N], val[N], ans[N];
vector<int> cnt[N];
int e, dep; void init(void) {
memset (head, -1, sizeof (head));
e = 0; dep = 0;
} void add_edge(int u, int v) {
edge[e].v = v; edge[e].nex = head[u];
head[u] = e++;
} bool cmp(int i, int j) {
return w[i] < w[j];
} void compress(int n) {
for (int i=1; i<=n; ++i) p[i] = i;
sort (p+1, p+1+n, cmp);
int rk = 0, pre = w[p[1]] - 1;
for (int i=1; i<=n; ++i) {
if (pre != w[p[i]]) {
pre = w[p[i]];
w[p[i]] = ++rk;
}
else {
w[p[i]] = rk;
}
}
} void DFS(int u, int fa) {
dfn[u] = ++dep; val[dep] = w[u];
for (int i=head[u]; ~i; i=edge[i].nex) {
int v = edge[i].v;
if (v == fa) continue;
DFS (v, u);
}
low[u] = dep;
} int main(void) {
int T, cas = 0; scanf ("%d", &T);
while (T--) {
if (cas) puts ("");
printf ("Case #%d:\n", ++cas);
int n, k; scanf ("%d%d", &n, &k);
init (); for (int i=1; i<=n; ++i) {
scanf ("%d", &w[i]);
}
compress (n); //离散化,升序排序,相同的还是相同的 for (int u, v, i=1; i<n; ++i) {
scanf ("%d%d", &u, &v);
add_edge (u, v); add_edge (v, u);
}
DFS (1, -1); //先序遍历,得到DFS序,树形变线形 int m; scanf ("%d", &m);
for (int u, i=1; i<=m; ++i) {
scanf ("%d", &u);
q[i] = Query (dfn[u], low[u], i);
}
sort (q+1, q+1+m); //按照DFS序排序 for (int i=1; i<=n; ++i) cnt[i].clear ();
int qu = 1; bit.init ();
for (int i=1; i<=n; ++i) { //按照dep深度从小到大
int v = val[i];
cnt[v].push_back (i); //表示离散后的相同的权值的个数
int sz = cnt[v].size ();
if (sz >= k) {
if (sz == k) bit.updata (cnt[v][sz-k], 1);
else {
bit.updata (cnt[v][sz-k-1], -2); //?
bit.updata (cnt[v][sz-k], 1);
}
}
while (qu <= m && q[qu].r == i) {
ans[q[qu].id] = bit.query (q[qu].r) - bit.query (q[qu].l - 1);
qu++;
}
} for (int i=1; i<=m; ++i) {
printf ("%d\n", ans[i]);
}
} return 0;
}

代码(莫队算法):

/************************************************
* Author :Running_Time
* Created Time :2015/9/10 星期四 19:15:22
* File Name :I.cpp
************************************************/ #include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std; #define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
struct Edge {
int v, nex;
}edge[N*2];
struct Data {
int l, r, id, b;
Data () {}
Data (int l, int r, int id, int b) : l (l), r (r), id (id), b (b) {}
bool operator < (const Data &x) const {
if (b == x.b) return r < x.r;
else return b < x.b;
}
}data[N];
int head[N], dfn[N], low[N], w[N], p[N], val[N], ans[N];
int cnt[N];
int n, k, m, e, dep, sum; void init(void) {
memset (head, -1, sizeof (head));
e = 0; dep = 0;
} void add_edge(int u, int v) {
edge[e].v = v; edge[e].nex = head[u];
head[u] = e++;
} bool cmp(int i, int j) {
return w[i] < w[j];
} void compress(int n) {
for (int i=1; i<=n; ++i) p[i] = i;
sort (p+1, p+1+n, cmp);
int rk = 0, pre = w[p[1]] - 1;
for (int i=1; i<=n; ++i) {
if (pre != w[p[i]]) {
pre = w[p[i]];
w[p[i]] = ++rk;
}
else {
w[p[i]] = rk;
}
}
} void DFS(int u, int fa) {
dfn[u] = ++dep; val[dep] = w[u];
for (int i=head[u]; ~i; i=edge[i].nex) {
int v = edge[i].v;
if (v == fa) continue;
DFS (v, u);
}
low[u] = dep;
} inline void updata(int x, int c) {
cnt[x] += c;
if (cnt[x] == k) sum++;
else if (c > 0 && cnt[x] == k + 1) sum--;
else if (c < 0 && cnt[x] == k - 1) sum--;
} void Modui(void) {
memset (cnt, 0, sizeof (cnt));
sum = 0;
int l = 1, r = 0;
for (int i=1; i<=m; ++i) {
while (data[i].l < l) updata (val[--l], 1);
while (data[i].l > l) updata (val[l], -1), l++;
while (data[i].r > r) updata (val[++r], 1);
while (data[i].r < r) updata (val[r], -1), r--;
ans[data[i].id] = sum;
}
for (int i=1; i<=m; ++i) {
printf ("%d\n", ans[i]);
}
} int main(void) {
int T, cas = 0; scanf ("%d", &T);
while (T--) {
if (cas) puts ("");
printf ("Case #%d:\n", ++cas);
scanf ("%d%d", &n, &k);
init (); for (int i=1; i<=n; ++i) {
scanf ("%d", &w[i]);
}
compress (n); //离散化,升序排序,相同的还是相同的 for (int u, v, i=1; i<n; ++i) {
scanf ("%d%d", &u, &v);
add_edge (u, v); add_edge (v, u);
}
DFS (1, -1); //先序遍历,得到DFS序,树形变线形 int block = (int) sqrt (n + 0.5);
scanf ("%d", &m);
for (int u, i=1; i<=m; ++i) {
scanf ("%d", &u);
data[i] = Data (dfn[u], low[u], i, dfn[u] / block);
}
sort (data+1, data+1+m); //按照DFS序排序
Modui ();
} return 0;
}

  

Codeforces Round #136 (Div. 1) B. Little Elephant and Array

题目传送门

分析:估计这是上面那道题的母题(弱化版),直接套用就行了,现在稍微理解了树状数组的维护方法,配上图:

代码(树状数组):

/************************************************
* Author :Running_Time
* Created Time :2015/9/11 星期五 18:39:17
* File Name :B.cpp
************************************************/ #include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std; #define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int n, m;
struct BIT {
int c[N];
void init(void) {
memset (c, 0, sizeof (c));
}
void updata(int i, int x) {
while (i <= n) {
c[i] += x; i += i & (-i);
}
}
int query(int i) {
int ret = 0;
while (i) {
ret += c[i]; i -= i & (-i);
}
return ret;
}
}bit;
struct Query {
int l, r, id;
bool operator < (const Query &x) const {
return r < x.r;
}
}q[N];
int a[N], ans[N];
vector<int> cnt[N]; int main(void) {
scanf ("%d%d", &n, &m);
for (int i=1; i<=n; ++i) scanf ("%d", &a[i]);
for (int i=1; i<=m; ++i) {
scanf ("%d%d", &q[i].l, &q[i].r);
q[i].id = i;
}
sort (q+1, q+1+m);
int qu = 1;
for (int i=1; i<=n; ++i) cnt[i].clear ();
bit.init ();
for (int i=1; i<=n; ++i) {
if (a[i] > n) continue;
cnt[a[i]].push_back (i);
int sz = cnt[a[i]].size ();
if (sz >= a[i]) {
bit.updata (cnt[a[i]][sz-a[i]], 1);
if (sz > a[i]) bit.updata (cnt[a[i]][sz-a[i]-1], -2);
if (sz > a[i] + 1) bit.updata (cnt[a[i]][sz-a[i]-2], 1);
}
while (qu <= m && q[qu].r == i) {
ans[q[qu].id] = bit.query (q[qu].r) - bit.query (q[qu].l - 1);
qu++;
}
}
for (int i=1; i<=m; ++i) {
printf ("%d\n", ans[i]);
} return 0;
}

  

 代码(莫队):

/************************************************
* Author :Running_Time
* Created Time :2015/9/11 星期五 20:05:22
* File Name :B_Modui.cpp
************************************************/ #include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std; #define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
struct Data {
int l, r, id, b;
bool operator < (const Data &x) const {
if (b == x.b) return r < x.r;
else return b < x.b;
}
}data[N];
int a[N], ans[N], cnt[N];
int n, m, sum; inline void updata(int x, int c) {
if (x > n) return ;
cnt[x] += c;
if (cnt[x] == x) sum++;
else if (c > 0 && cnt[x] == x + 1) sum--;
else if (c < 0 && cnt[x] == x - 1) sum--;
} void Modui(void) {
sum = 0;
memset (cnt, 0, sizeof (cnt));
int l = 1, r = 0;
for (int i=1; i<=m; ++i) {
while (data[i].l < l) updata (a[--l], 1);
while (data[i].l > l) updata (a[l], -1), l++;
while (data[i].r > r) updata (a[++r], 1);
while (data[i].r < r) updata (a[r], -1), r--;
ans[data[i].id] = sum;
}
for (int i=1; i<=m; ++i) {
printf ("%d\n", ans[i]);
}
} int main(void) {
scanf ("%d%d", &n, &m);
int block = (int) sqrt (n + 0.5);
for (int i=1; i<=n; ++i) {
scanf ("%d", &a[i]);
}
for (int i=1; i<=m; ++i) {
scanf ("%d%d", &data[i].l, &data[i].r);
data[i].id = i; data[i].b = data[i].l / block;
}
sort (data+1, data+1+m);
Modui (); return 0;
}

  

(好题)树状数组+离散化+DFS序+离线/莫队 HDOJ 4358 Boring counting的更多相关文章

  1. hdu4605 树状数组+离散化+dfs

    Magic Ball Game Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  2. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  3. BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)

    题目大意: Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  4. POJ 2299 Ultra-QuickSort (树状数组 && 离散化&&逆序)

    题意 : 给出一个数n(n<500,000), 再给出n个数的序列 a1.a2.....an每一个ai的范围是 0~999,999,999  要求出当通过相邻两项交换的方法进行升序排序时需要交换 ...

  5. Codeforces 1111E DP + 树状数组 + LCA + dfs序

    题意:给你一颗树,有q次询问,每次询问给你若干个点,这些点可以最多分出m组,每组要满足两个条件:1:每组至少一个点,2:组内的点不能是组内其它点的祖先,问这样的分组能有多少个? 思路:https:// ...

  6. Ultra-QuickSort(树状数组求逆序对数)

    Ultra-QuickSort 题目链接:http://poj.org/problem?id=2299 Time Limit: 7000MS   Memory Limit: 65536K Total ...

  7. BZOJ_5055_膜法师_树状数组+离散化

    BZOJ_5055_膜法师_树状数组+离散化 Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然 ...

  8. hdu2838树状数组解逆序

    离散化和排序后的序号问题搞得我实在是头痛 不过树状数组解逆序和偏序一类问题真的好用 更新:hdu的数据弱的真实,我交上去错的代价也对了.. 下面的代码是错的 /* 每个点的贡献度=权值*在这个点之前的 ...

  9. BZOJ3289[JZYZOJP2018]: Mato的文件管理 莫队+树状数组+离散化

            描述 Description     Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号.为了防止他人偷拷,这些资料都是加密过的, ...

随机推荐

  1. java学习方向及主要内容

    Java分成J2ME(移动应用开发),J2SE(桌面应用开发),J2EE(Web企业级应用),所以java并不是单机版的,只是面向对象语言.建议如果学习java体系的话可以这样去学习: *第一阶段:J ...

  2. hadoop shuffle

    1 hadoop shuffle的地位 hadoop  shuffle是map reduce算法的核心,是它连接了多个map和多个reduce,它将map的输出交给reduce作为输入. 2 hado ...

  3. compile java sources

    Information:javac 1.8.0_91 was used to compile java sources D:\myjdk\bin\java "-javaagent:C:\Pr ...

  4. Cocos2d-js异步图片加载

    这里说的是在需要的使用加载图片,比如游戏中的某个关卡的图片,不用在游戏一开始就加载(万一用户玩不到那关,岂不是很冤,流量费了那么多),否则 载入速度也慢.这种方式加载资源要用到cc.loader官方文 ...

  5. hihoCoder 1582 Territorial Dispute 【凸包】(ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛)

    #1582 : Territorial Dispute 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 In 2333, the C++ Empire and the Ja ...

  6. JVM垃圾回收算法 及 垃圾收集器

    摘自<深入理解Java虚拟机> 一.什么是: GC算法是 方法论,那么垃圾收集器就是具体的 实现. 二.四种 垃圾回收算法 1.标记-清除算法:最基础的收集算法:不足有两点:1标记和清除两 ...

  7. HDU3081 Marriage Match II —— 传递闭包 + 二分图最大匹配 or 传递闭包 + 二分 + 最大流

    题目链接:https://vjudge.net/problem/HDU-3081 Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    ...

  8. POJ3281 Dining —— 最大流 + 拆点

    题目链接:https://vjudge.net/problem/POJ-3281 Dining Time Limit: 2000MS   Memory Limit: 65536K Total Subm ...

  9. HDU1693 Eat the Trees —— 插头DP

    题目链接:https://vjudge.net/problem/HDU-1693 Eat the Trees Time Limit: 4000/2000 MS (Java/Others)    Mem ...

  10. YTU 2425: C语言习题 输出月份

    2425: C语言习题 输出月份 时间限制: 1 Sec  内存限制: 128 MB 提交: 476  解决: 287 题目描述 编写一程序,输入月份号,输出该月的英文月名.例如,输入3,则输出Mar ...