codeforces 375D . Tree and Queries 启发式合并 || dfs序+莫队

题目链接

一个n个节点的树, 每一个节点有一个颜色, 1是根节点。 m个询问, 每个询问给出u, k。 输出u的子树中出现次数大于等于k的颜色的数量。

启发式合并, 先将输入读进来, 然后dfs完一个节点就处理跟它有关的询问。

感觉不是很难, 然而.....WA了n次最后还是看的别人的代码

  1 #include <iostream>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <map>
  8 #include <set>
  9 #include <string>
 10 #include <queue>
 11 #include <stack>
 12 #include <bitset>
 13 using namespace std;
 14 #define pb(x) push_back(x)
 15 #define ll long long
 16 #define mk(x, y) make_pair(x, y)
 17 #define lson l, m, rt<<1
 18 #define mem(a) memset(a, 0, sizeof(a))
 19 #define rson m+1, r, rt<<1|1
 20 #define mem1(a) memset(a, -1, sizeof(a))
 21 #define mem2(a) memset(a, 0x3f, sizeof(a))
 22 #define rep(i, n, a) for(int i = a; i<n; i++)
 23 #define fi first
 24 #define se second
 25 typedef pair<int, int> pll;
 26 const double PI = acos(-1.0);
 27 const double eps = 1e-8;
 28 const int mod = 1e9+7;
 29 const int inf = 1061109567;
 30 const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
 31 const int maxn = 1e5+5;
 32 int head[maxn*2], num, id[maxn], val[maxn], ans[maxn];
 33 struct node
 34 {
 35     int to, nextt, w;
 36 }e[maxn*2];
 37 void add(int u, int v) {
 38     e[num].to = v, e[num].nextt = head[u], head[u] = num++;
 39 }
 40 void init() {
 41     num = 0;
 42     mem1(head);
 43 }
 44 struct Node
 45 {
 46     map <int, int> mp;
 47     vector <int> ve;
 48     int sz = 0;
 49     void add(int x) {
 50         mp[x]++;
 51         while(mp[x]>=ve.size()) {
 52             ve.push_back(0);
 53         }
 54         ve[mp[x]]++;
 55         sz++;
 56     }
 57 }st[maxn];
 58 vector <pll> v[maxn];
 59 void combine(int& x, int& y) {
 60     if(st[x].sz<st[y].sz)
 61         swap(x, y);
 62     for(auto it = st[y].mp.begin(); it!=st[y].mp.end(); it++) {
 63         for(int i = 0; i<it->second; i++) {
 64             st[x].add(it->first);
 65         }
 66     }
 67 }
 68 void dfs(int u, int fa) {
 69     st[u].add(val[u]);
 70     for(int i = head[u]; ~i; i = e[i].nextt) {
 71         int vx = e[i].to;
 72         if(vx == fa)
 73             continue;
 74         dfs(vx, u);
 75         combine(id[u], id[vx]);
 76     }
 77     for(int i = 0; i<v[u].size(); i++) {
 78         int x = v[u][i].fi, y = v[u][i].se;
 79         if(x>=st[id[u]].ve.size())
 80             continue;
 81         ans[y] = st[id[u]].ve[x];
 82     }
 83 }
 84 int main()
 85 {
 86     int n, m, x, y;
 87     cin>>n>>m;
 88     init();
 89     for(int i = 1; i<=n; i++) {
 90         scanf("%d", &val[i]);
 91         id[i] = i;
 92     }
 93     for(int i = 0; i<n-1; i++) {
 94         scanf("%d%d", &x, &y);
 95         add(x, y);
 96         add(y, x);
 97     }
 98     for(int i = 0; i<m; ++i) {
 99         scanf("%d%d", &x, &y);
100         v[x].pb(mk(y, i));
101     }
102     dfs(1, 0);
103     for(int i = 0; i<m; i++)
104         cout<<ans[i]<<endl;
105     return 0;
106 }
时间: 2025-01-10 06:29:45

codeforces 375D . Tree and Queries 启发式合并 || dfs序+莫队的相关文章

CodeForces 375D. Tree and Queries【树上启发式合并】

传送门 题意 给出一棵 \(n\) 个结点的树,每个结点有一个颜色 \(c_i\) . 询问 \(q\) 次,每次询问以 \(v\) 结点为根的子树中,出现次数 \(\ge k\) 的颜色有多少种.树的根节点是 \(1\). 题解 反正我看见这个 \(\ge k\) 就觉得要用线段树,实际上好像不用写线段树的 Orz. 还是树上启发式合并,记录每种颜色出现的次数,然后线段树记录某种次数有多少颜色,更改就在线段树上改. 这是最后一道树上启发式合并的例题了,以后遇到再刷. #include <bit

Codeforces 375D Tree and Queries(DFS序+莫队+树状数组)

题目链接  Tree and Queries 题目大意  给出一棵树和每个节点的颜色.每次询问vj, kj 你需要回答在以vj为根的子树中满足条件的的颜色数目, 条件:具有该颜色的节点数量至少为kj. (莫队居然可以过) 首先转DFS序,这样就变成了区间查询. 然后直接套用莫队,求出每次询问状态下的t[],t[k]表示当前区间内拥有k个节点的颜色数量. 然后统计t[k] + t[k + 1], ..., t[MAX]即可,这个过程用树状数组维护. #include <bits/stdc++.h>

CodeForces 375D Tree and Queries 莫队||DFS序

Tree and Queries 题意:有一颗以1号节点为根的树,每一个节点有一个自己的颜色,求出节点v的子数上颜色出现次数>=k的颜色种类. 题解:使用莫队处理这个问题,将树转变成DFS序区间,然后就是开一个数据记录下出现次数为k次的颜色数目,查询的时候直接返回这个数组中的对应的值就行了. 注意的就是记得将节点的颜色传递给dfs序对应位置的颜色. 这个忘记了找了好久的bug. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3

CF 375D. Tree and Queries【莫队】

题意: 一棵树,询问一个子树内出现次数≥k≥k的颜色有几种 强制在线见上一道 用莫队不知道比分块高到哪里去了,超好写不用调7倍速度!!! 可以用分块维护出现次数这个权值,实现$O(1)-O(\sqrt{N})$修改查询 #pragma GCC optimize ("O2") #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #incl

HDU5293(SummerTrainingDay13-B Tree DP + 树状数组 + dfs序)

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1798    Accepted Submission(s): 585 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n.The

570D Codeforces Round #316 (Div. 2) D(dfs序,时间戳,二分

题目:一棵树上每个节点有个字符值,询问每个节点的深度为h的子节点的字符是否能组成一个回文串. 思路:首先是奇妙的dfs序和时间戳,通过记录每个节点的dfs进出时间,可以发现某个节点的子节点的进出时间均在该节点的进出时间范围内(这是很直观的dfs的性质),这样可以把树形结构转变为线性结构,方便进行各种处理.dfs一遍处理时间戳,每个节点的深度,并记录每个深度的节点都有哪些,此时每个深度的节点就是排好序的.然后对于一个询问,可以利用二分查找确定子节点在该层的哪一段.对于每一层,预先处理每个字符的前缀

HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形dp, 对于每条链u,v,w,我们只在lca(u,v)的顶点上处理它 让dp[i]表示以i为根的指数的最大值,sum[i]表示dp[vi]的和(vi为i的儿子们) 则i点有两种决策,一种是不选以i为lca的链,则dp[i]=sum[i]. 另一种是选一条以i为lca的链,那么有转移方程:dp[i]=

Tree and Queries CodeForces - 375D 树上莫队

http://codeforces.com/problemset/problem/375/D 树莫队就是把树用dfs序变成线性的数组. (原数组要根据dfs的顺序来变化) 然后和莫队一样的区间询问. 这题和普通莫队有点区别,他需要的不单单是统计区间元素种类个数,是区间元素种类个数 >= k[i]的个数. 考虑最简单的用bit维护,复杂度多了个log 观察到每次只需要 + 1  或者 -1 用一个数组sum[k]表示种类数大于等于k的ans 在numc[val]++之后,sum[numc[val]

Codeforces 375D D. Tree and Queries

传送门 题意: 给一棵树,每个节点有一个颜色,询问x为根的子树,出现次数大于等于k的颜色个数. 输入格式: 第一行 2 个数 n,m 表示节点数和询问数. 接下来一行 n 个数,第 i 个数 ci ?表示节点 i 的颜色. 接下来 n-1 行,每行两个数 a,b 表示一条边. 接下来 m 行,每行两个数 x,k 表示一组询问. 数据范围: $n.m,c,k \in [1,10^5]$ 显然可以 $dsu\ on\ tree$ 可以用权值树状数组直接维护当前每个出现次数大于等于 $k$ 的颜色数量