HDU 5678 ztr loves trees

这题也是一眼标算.....

先搞一次dfs,把树转换成序列,对每个节点看子树的中位数,也就是看某段区间的中位数,这样就可以主席树求区间第k大值解决。

注意:询问的次数有1000000次,每次去询问会TLE的。注意到询问的种类只有100000种,所以之前询问过的可以0(1)得到,或者直接处理出每一种询问的答案。

还有一个问题:小数取模...用fmod函数。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;

inline bool scan_d(int &num)
{
    char in; bool IsN = false;
    in = getchar();
    if (in == EOF) return false;
    while (in != '-' && (in<'0' || in>'9')) in = getchar();
    if (in == '-'){ IsN = true; num = 0; }
    else num = in - '0';
    while (in = getchar(), in >= '0'&&in <= '9'){
        num *= 10, num += in - '0';
    }
    if (IsN) num = -num;
    return true;
}

#define mod 1000000007
const int maxn = 100010;
double Ans[maxn];
vector<int>Tree[maxn];
int tmp_n, Q;
int val[maxn];
int L[maxn], R[maxn];
int time;

const int MAXN = 200010;
const int M = MAXN * 30;
int n, q, m, tot;
int a[MAXN], t[MAXN];
int T[M], lson[M], rson[M], c[M];

void Init_hash()
{
    for (int i = 1; i <= n; i++)
        t[i] = a[i];
    sort(t + 1, t + 1 + n);
    m = unique(t + 1, t + 1 + n) - t - 1;
}
int build(int l, int r)
{
    int root = tot++;
    c[root] = 0;
    if (l != r)
    {
        int mid = (l + r) >> 1;
        lson[root] = build(l, mid);
        rson[root] = build(mid + 1, r);
    }
    return root;
}
int HASH(int x)
{
    return lower_bound(t + 1, t + 1 + m, x) - t;
}
int update(int root, int pos, int val)
{
    int newroot = tot++, tmp = newroot;
    c[newroot] = c[root] + val;
    int l = 1, r = m;
    while (l < r)
    {
        int mid = (l + r) >> 1;
        if (pos <= mid)
        {
            lson[newroot] = tot++; rson[newroot] = rson[root];
            newroot = lson[newroot]; root = lson[root];
            r = mid;
        }
        else
        {
            rson[newroot] = tot++; lson[newroot] = lson[root];
            newroot = rson[newroot]; root = rson[root];
            l = mid + 1;
        }
        c[newroot] = c[root] + val;
    }
    return tmp;
}
int query(int left_root, int right_root, int k)
{
    int l = 1, r = m;
    while (l < r)
    {
        int mid = (l + r) >> 1;
        if (c[lson[left_root]] - c[lson[right_root]] >= k)
        {
            r = mid;
            left_root = lson[left_root];
            right_root = lson[right_root];
        }
        else
        {
            l = mid + 1;
            k -= c[lson[left_root]] - c[lson[right_root]];
            left_root = rson[left_root];
            right_root = rson[right_root];
        }
    }
    return l;
}

void dfs(int now)
{
    L[now] = ++time;
    a[time] = val[now];
    for (int i = 0; i < Tree[now].size(); i++)
        dfs(Tree[now][i]);
    R[now] = ++time;
    a[time] = val[now];
}

int main()
{
    int Case; scanf("%d", &Case);
    while (Case--)
    {
        scanf("%d%d", &tmp_n, &Q);

        for (int i = 1; i <= tmp_n; i++)
        {
            scan_d(val[i]);
            Tree[i].clear();
        }

        for (int i = 1; i <= tmp_n - 1; i++)
        {
            int u, v;
            scan_d(u); scan_d(v);
            Tree[u].push_back(v);
        }

        time = 0; 
        dfs(1);
        n = time;

        tot = 0;
        Init_hash();

        T[n + 1] = build(1, m);

        for (int i = n; i; i--)
        {
            int pos = HASH(a[i]);
            T[i] = update(T[i + 1], pos, 1);
        }

        for (int i = 1; i <= tmp_n; i++)
        {
            int l = L[i], r = R[i];
            if ((l - r + 1) % 2 == 1)
            {
                int k = (l + r) / 2 - l + 1;
                Ans[i] = 1.0*t[query(T[l], T[r + 1], k)];
            }
            else
            {
                int k1 = (l + r) / 2 - l + 1;
                int k2 = (l + r) / 2 - l + 2;
                Ans[i] = 1.0*(t[query(T[l], T[r + 1], k1)] + t[query(T[l], T[r + 1], k2)]) / 2.0;
            }
        }
        double f = 0;

        for (int i = 1; i <= Q; i++)
        {
            int id; scan_d(id);
            f = fmod(f * 10 + Ans[id], mod);
        }
        printf("%.1lf\n", f);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/zufezzt/p/5450499.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值