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]]++,表明这个种类出现次数是numc[val]次的贡献递增1

在num[val]--之前,就需要把sum[numc[val]]--,表明贡献减1了

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 1e5 + 20;
struct Edge {
    int u, v, tonext;
}e[maxn * 2];
int first[maxn], num;
int c[maxn];
void addEdge(int u, int v) {
    ++num;
    e[num].u = u, e[num].v = v, e[num].tonext = first[u];
    first[u] = num;
}
int L[maxn], R[maxn], dfs_clock;
int color[maxn];
void dfs(int cur, int fa) {
    L[cur] = ++dfs_clock;
    color[dfs_clock] = c[cur];
    for (int i = first[cur]; i; i = e[i].tonext) {
        int v = e[i].v;
        if (fa == v) continue;
        dfs(v, cur);
    }
    R[cur] = dfs_clock;
}
int magic;
struct Node {
    int L, R, k, id;
    bool operator < (const struct Node & rhs) const {
        if (L / magic != rhs.L / magic) return L / magic < rhs.L / magic;
        else return R < rhs.R;
    }
}query[maxn];
int ans[maxn], numc[maxn];
int bit[maxn];
int lowbit(int x) {
    return x & (-x);
}
void add(int pos, int val) {
    while (pos) {
        bit[pos] += val;
        pos -= lowbit(pos);
    }
}
int ask(int pos) {
    int ans = 0;
    while (pos <= maxn - 20) {
        ans += bit[pos];
        pos += lowbit(pos);
    }
    return ans;
}
int suffix[maxn];
void work() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) cin >> c[i];
    for (int i = 1; i <= n - 1; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        addEdge(u, v);
        addEdge(v, u);
    }
    dfs(1, 0);
    magic = (int)sqrt(n + 0.5);
    for (int i = 1; i <= m; ++i) {
        int which, k;
        scanf("%d%d", &which, &k);
        query[i].L = L[which], query[i].R = R[which], query[i].k = k;
        query[i].id = i;
    }
    sort(query + 1, query + 1 + m);
    int L = 1, R = 0;
    int temp = 0;
    for (int i = 1; i <= m; ++i) {
        while (R < query[i].R) {
            ++R;
            suffix[++numc[color[R]]]++;
        }
        while (R > query[i].R) {
            suffix[numc[color[R]]--]--;
            --R;
        }
        while (L < query[i].L) {
            suffix[numc[color[L]]--]--;
            L++;
        }
        while (L > query[i].L) {
            L--;
            suffix[++numc[color[L]]]++;
        }
        ans[query[i].id] = suffix[query[i].k];
    }
    for (int i = 1; i <= m; ++i) {
        printf("%d\n", ans[i]);
    }
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
时间: 2024-08-08 22:00:09

Tree and Queries CodeForces - 375D 树上莫队的相关文章

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>

Count on a tree II(树上莫队)

Count on a tree II(luogu) Description 题目描述 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. 输入格式 第一行有两个整数n和m(n=40000,m=100000). 第二行有n个整数.第i个整数表示第i个节点表示的整数. 在接下来的n-1行中,每行包含两个整数u v,描述一条边(u,v). 在接下来的m行中,每一行包含两个整数u v,询问u到v的路径上有多少个不同的整数. 输出格式 对于每个询问,输出结果. Solutio

SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无意中看到树上莫队,只是拿来练练,没有想到这题的难点不在于树上莫队,而是判断LCA是否在两点之间的路径上的问题.耗时1天. 树上莫队的搞法就是: (1)DFS一次,对树进行分块,分成sqrt(n)块,每个点属于一个块.并记录每个点的DFS序. (2)将m个询问区间用所属块号作为第一关键字,DFS序作为第二关键字

[spoj COT2]树上莫队

题目链接:http://www.spoj.com/problems/COT2/ 学会了树上莫队,真的是太激动了!参照博客:http://codeforces.com/blog/entry/43230 讲的十分清楚. #include<bits/stdc++.h> using namespace std; const int MAXN=40005; const int maxm=100005; int cur; int sat[MAXN]; int ean[MAXN]; int A[MAXN*2

【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)

学习了树上莫队,树分块后对讯问的$dfs序$排序,然后就可以滑动树链处理答案了. 关于树链的滑动,只需要特殊处理一下$LCA$就行了. 在这里一条树链保留下来给后面的链来转移的$now$的为这条树链上所有点除去$LCA$的颜色种数.因为如果要考虑$LCA$情况就太多了,不如单独考虑$LCA$. 转移后加上当前链的$LCA$进行统计,然后再去掉这个$LCA$更新一下$now$值给后面的链转移. 这都是我的理解,说的有点不清楚,具体请看vfk的题解 OTZ 虽然不是这道题,但是通过这篇博客学习树上莫

(树上莫队)HDU - 5799 This world need more Zhu

题意: 两种询问: 1.询问以u为根的子树中出现的a次的数的和与出现b次的数的和的gcd. 2.询问u到v的树链中出现的a次的数的和与出现b次的数的和的gcd. 有点绕.. 分析: 因为自己不会树上莫队,所以学习了一波. 但是对于子树我还是有所经验,可以转成dfs序来做,之前有做过类似的题,比如这题. 然而对于树链有点懵逼,虽然我觉得也能用dfs序做,不过看大佬们的dfs序做的树链查询,也有点懵,感觉写起来很麻烦. 貌似是修改了dfs序,回溯的时候不再只是和进入时相同的序,而是独立的序. 还是感

【BZOJ-3757】苹果树 块状树 + 树上莫队

3757: 苹果树 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1305  Solved: 503[Submit][Status][Discuss] Description 神犇家门口种了一棵苹果树.苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条.由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色.我们用一个到n之间的正整数来表示一种颜色.树上

bzoj 3757: 苹果树(树上莫队)

3757: 苹果树 Time Limit: 20 Sec  Memory Limit: 256 MB Submit: 1327  Solved: 510 [Submit][Status][Discuss] Description 神犇家门口种了一棵苹果树.苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条.由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色.我们用一个1到n之间的正整数来表示一种颜色

[BZOJ 3052] [wc2013] 糖果公园 【树上莫队】

题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之后为第三关键字 排序. 我们将块的大小设置在 n^(2/3) ,这样一共有 n^(1/3) 个块.最后算法的总复杂度会是 n^(5/3) . 每一次如何从上一个询问转移来呢? 假设上一个询问是 (lx, ly, lt) ,这次的询问是 (x, y, t) .t 代表是在第 t 次修改操作之后. 首先