HDU 4358

将树形结构转化成线性结构,那么我们就可以将问题转化为求一个区间内,恰好出现K次的权值有多少种。我们记录树状数组第k位表示ki的答案,假设v出现的位置是p1; p2; p3;    ; pk,那么我们假设现在枚举到了pk这个位置,将pk这个位置的数字加入集合之后,p(k−K−1) + 1p(k−K)这部分区间内权值v出现次数就超过K了,p(k−K )+ 1p(k−K+1)这部分区间内权值v出现的次数恰好达K,所以我们将树状数组中的p(k−K−1) + 1p(k−K)内的值全部减1p(k−K) +1p(k−K+1)内的值全部加1。查询的时候是查询左端点前数的和。


#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int MAXN = 100010;
const int MAXQ = 100010;
int add[MAXN<<2];

struct Edge {
    int u, v, next;
    Edge() {}
    Edge(int t_u, int t_v) : u(t_u), v(t_v) {}
}edges[2*MAXN];
int head[MAXN], edge_sum;
int T, N, K, Q;
int L[MAXN], R[MAXN];
int W[MAXN], A[MAXN];
bool visit[MAXN];
int id;
map<int,int> myMap;
vector<int> vec[MAXN];
int ans[MAXN];

void init() {
    edge_sum = 0;
    memset(head, -1, sizeof(head));
    memset(visit, false, sizeof(visit));
}

void addEdge(int u, int v) {
    edges[edge_sum].u = u;
    edges[edge_sum].v = v;
    edges[edge_sum].next = head[u];
    head[u] = edge_sum++;

    edges[edge_sum].u = v;
    edges[edge_sum].v = u;
    edges[edge_sum].next = head[v];
    head[v] = edge_sum++;
}

void dfs(int u) {
    visit[u] = true;
    L[u] = ++id;
    A[id] = W[u];
    for(int i = head[u]; i != -1; i = edges[i].next) {
        int v = edges[i].v;
        if(!visit[v]) {
            dfs(v);
        }
    }
    R[u] = id;
    return ;
}

void pushdown(int rt) {
    if(add[rt]) {
        add[rt<<1] += add[rt];
        add[rt<<1|1] += add[rt];
        add[rt] = 0;
    }
    return ;
}

void bulid(int l, int r, int rt) {
    add[rt] = 0;
    if(l == r) return ;
    int m = (l + r)>>1;
    bulid(l, m, rt<<1);
    bulid(m + 1, r, rt<<1|1);
    return ;
}

void update(int l, int r, int rt, int L, int R, int c) {

    if(L == l && R == r) {
        add[rt] += c;
        return ;
    }
    pushdown(rt);
    int m = (l + r)>>1;
    if(R <= m) {
        update(l, m, rt<<1, L, R, c);
    } else if(L > m) {
        update(m + 1, r, rt<<1|1, L, R, c);
    } else {
        update(l, m, rt<<1, L, m, c);
        update(m + 1, r, rt<<1|1, m + 1, R, c);
    }
    return ;
}

int query(int l, int r, int rt, int pos) {
    if(l == r) {
        return add[rt];
    }
    pushdown(rt);
    int m = (l + r)>>1;
    if(pos <= m) return query(l, m, rt<<1, pos);
    else return query(m + 1, r, rt<<1|1, pos);
}

struct Query {
    int l, r, id;
    Query() {}
    Query(int t_l, int t_r, int t_id) : l(t_l), r(t_r), id(t_id) {}
    friend bool operator < (const Query &q1, const Query &q2) {
        if(q1.r == q2.r) {
            return q1.l < q2.l;
        }
        return q1.r < q2.r;
    }
}QQ[MAXQ];

int main() {

    //freopen("aa.in", "r", stdin);

    int u, v;
    scanf("%d", &T);
    for(int kcase = 1; kcase <= T; ++kcase) {
        if(kcase > 1) puts("");
        scanf("%d %d", &N, &K);
        init(); myMap.clear(); id = 0;
        for(int i = 0; i <= N; ++i) {
            vec[i].clear();
        }
        for(int i = 1; i <= N; ++i) {
            scanf("%d", &W[i]);
            if(myMap.count(W[i]) == 0) {
                myMap[W[i]] = ++id;
            }
            W[i] = myMap[W[i]];
        }
        for(int i = 1; i < N; ++i) {
            scanf("%d %d", &u, &v);
            addEdge(u, v);
        }
        id = 0; dfs(1);
        scanf("%d", &Q);
        for(int i = 1; i <= Q; ++i) {
            scanf("%d", &u);
            QQ[i].l = L[u];
            QQ[i].r = R[u];
            QQ[i].id = i;
        }
        sort(QQ + 1, QQ + Q + 1); id = 1;
        bulid(1, N, 1);
        for(int i = 1; i <= N; ++i) {
            int val = A[i];
            vec[val].push_back(i);
            int size = vec[val].size();
            if(size >= K) {
                if(size == K) {
                    update(1, N, 1, 1, vec[val][size-K], 1);
                } else {
                    if(size - K - 2 >= 0) {
                        update(1, N, 1, vec[val][size-K-2]+1, vec[val][size-K-1], -1);
                    } else {
                        update(1, N, 1, 1, vec[val][size-K-1], -1);
                    }
                    update(1, N, 1, vec[val][size-K-1]+1, vec[val][size-K], 1);
                }
            }
            while(QQ[id].r == i) {
                ans[QQ[id].id] = query(1, N, 1, QQ[id].l);
                id++;
            }
        }
        printf("Case #%d:\n", kcase);
        for(int i = 1; i <= N; ++i) {
            printf("%d\n", ans[i]);
        }

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值