脑子不清醒的时候千万别写题。写题写不下去了千万别死扛,重构才是你唯一的出路QAQ

  昨天很想快点写道题,思路没有很清晰的时候就写了,结果……今天一怒之下决定重整思路重构代码,其实不过是半个小时的事情……

  提示很明显,总点数限制了范围。建立出虚树,在虚树上面 dp。 在虚树上面我们dp两遍,两遍一起处理出每一个(虚树上的)节点被谁管辖,在连接两者的路径上找到管理的分界点即可。处理两点之间的距离一定要上 ST 表啊……

#include <bits/stdc++.h>
using namespace std;
#define maxn 350000
#define CNST 20
int n, dep[maxn], gra[maxn][CNST];
int size[maxn], hson[maxn], ans[maxn];
int top, S[maxn], a[maxn], b[maxn];
int timer, dfn[maxn], sum[maxn];
bool mark[maxn], vis[maxn];
int T, Log[maxn * 2], bit[21], ST[maxn * 2][CNST], pos[maxn]; int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
} struct edge
{
    int cnp, to[maxn * 2], last[maxn * 2], head[maxn];
    edge() { cnp = 1; }
    void add(int u, int v)
    {
        if(u == v) return;
        to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;
        to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++;
    }
}E1, E2; bool cmp(int x, int y) { return dfn[x] < dfn[y]; } void dfs(int u, int fa)
{
    size[u] = 1; dfn[u] = ++ timer;
    gra[u][0] = fa; dep[u] = dep[fa] + 1; ST[++ T][0] = dep[u]; pos[u] = T;
    for(int i = 1; i < CNST; i ++) gra[u][i] = gra[gra[u][i - 1]][i - 1];
    for(int i = E1.head[u]; i; i = E1.last[i])
    {
        int v = E1.to[i];
        if(v == fa) return;
        dfs(v, u); size[u] += size[v];
        ST[++ T][0] = dep[u];
    }
} int LCA(int x, int y)
{
    if(dep[x] < dep[y]) swap(x, y);
    for(int i = CNST - 1; ~i; i --)
        if(dep[gra[x][i]] >= dep[y]) x = gra[x][i];
    for(int i = CNST - 1; ~i; i --)
        if(gra[x][i] != gra[y][i]) x = gra[x][i], y = gra[y][i];
    return (x == y) ? x : gra[x][0];
} int Get_Dis(int x, int y)
{
    int ret = dep[x] + dep[y];
    if(!x) return dep[y]; else if(!y) return dep[x];
    x = pos[x], y = pos[y];
    if(x > y) swap(x, y);
    int k = Log[y - x + 1];
    ret = ret - 2 * min(ST[x][k], ST[y - bit[k] + 1][k]);
    return ret;
} int Get_Gra(int x, int y)
{
    for(int i = CNST - 1; ~i; i --)
        if(dep[gra[x][i]] > dep[y]) x = gra[x][i];
    return x;
} int Work(int u, int v, int k)
{
    bool flag = 0;
    int x = u;
    for(int i = CNST - 1; i >= 0; i --)
    {
        int tem = gra[x][i]; if(dep[tem] < dep[k]) continue;
        int d1 = Get_Dis(u, tem), d2 = Get_Dis(v, tem);
        if(d1 < d2) x = gra[x][i];
        else if(d1 == d2 && u < v) x = gra[x][i];
    }
     return x;
} void DP(int u, int fa)
{
    hson[u] = 0; sum[u] = 0;
    for(int i = E2.head[u]; i; i = E2.last[i])
    {
        int v = E2.to[i]; if(!v) continue;
        if(v == fa) continue;
        DP(v, u);
        int t = hson[v];
        int dis = Get_Dis(u, t), dis2 = Get_Dis(u, hson[u]);
        if(dis < dis2) hson[u] = t;
        else if(dis == dis2 && t < hson[u]) hson[u] = t;
        if(!hson[u]) hson[u] = t;
    }
    if(mark[u]) hson[u] = u;
} void DP2(int u, int fa)
{
    int tot = 0;
    if(hson[fa])
    {
        int t = hson[fa];
        int dis = Get_Dis(u, t), dis2 = Get_Dis(u, hson[u]);
        if(dis < dis2) hson[u] = t;
        else if(dis == dis2 && t < hson[u]) hson[u] = t;
        if(!hson[u]) hson[u] = t;
    }
    for(int i = E2.head[u]; i; i = E2.last[i])
    {
        int v = E2.to[i];
        if(v == fa) continue; DP2(v, u);
        int y = Get_Gra(v, u);
        int x = Work(hson[v], hson[u], u);
        int tem = size[x] - size[v];
        ans[hson[v]] += tem, ans[hson[u]] += size[y] - size[x];
        tot += size[y];
    }
    ans[hson[u]] += size[u] - tot;
    E2.head[u] = 0;
} void Solve()
{
    int K = read();
    for(int i = 1; i <= K; i ++) b[i] = a[i] = read(), mark[a[i]] = 1;
    sort(a + 1, a + 1 + K, cmp); S[top = 1] = 1; E2.cnp = 1; ans[0] = 0;
    for(int i = 1; i <= K; i ++)
    {
        int lca = LCA(S[top], a[i]);
        while(2333)
        {
            if(dep[S[top - 1]] <= dep[lca])
            {
                E2.add(lca, S[top --]);
                if(lca != S[top]) S[++ top] = lca;
                break;
            }
            else E2.add(S[top], S[top - 1]), top --;
        }
        S[++ top] = a[i];
    }
    while(top > 1) E2.add(S[top], S[top - 1]), top --;
    sum[1] = 0; DP(1, 0); DP2(1, 0);
    for(int i = 1; i <= K; i ++) printf("%d ", ans[b[i]]), mark[b[i]] = 0, ans[b[i]] = 0;
    puts("");
} void init()
{
    bit[0] = 1; for(int i = 1; i <= 20; i ++) bit[i] = bit[i - 1] << 1;
    Log[0] = -1; for(int i = 1; i < maxn * 2; i ++) Log[i] = Log[i >> 1] + 1;
} int main()
{
    init(); n = read();
    for(int i = 1; i < n; i ++)
    {
        int x = read(), y = read();
        E1.add(x, y);
    }
    dfs(1, 0);
    for(int i = 1; i <= Log[T]; i ++)
        for(int j = 1; j + bit[i - 1] <= T; j ++)
            ST[j][i] = min(ST[j][i - 1], ST[j + bit[i - 1]][i - 1]);
    int q = read();
    for(int i = 1; i <= q; i ++) Solve();
    return 0;
}

【题解】HNOI2014世界树的更多相关文章

  1. [题解] [HNOI2014] 世界树

    题面 [HNOI2014]世界树 题解 从数据范围很容易看出是个虚树DP(可惜看出来了也还是不会做) 虚树大家应该都会, 不会的话自己去搜吧, 我懒得讲了, 我们在这里只需要考虑如何DP即可 首先我们 ...

  2. [BZOJ3572][Hnoi2014]世界树

    [BZOJ3572][Hnoi2014]世界树 试题描述 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条 ...

  3. 【BZOJ3572】[Hnoi2014]世界树 虚树

    [BZOJ3572][Hnoi2014]世界树 Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森 ...

  4. bzoj3572[Hnoi2014] 世界树 虚树+dp+倍增

    [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1921  Solved: 1019[Submit][Status][Dis ...

  5. BZOJ 3572: [Hnoi2014]世界树

    BZOJ 3572: [Hnoi2014]世界树 标签(空格分隔): OI-BZOJ OI-虚数 OI-树形dp OI-倍增 Time Limit: 20 Sec Memory Limit: 512 ...

  6. bzoj 3572: [Hnoi2014]世界树 虚树 && AC500

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 520  Solved: 300[Submit][Status] ...

  7. bzoj 3572 [Hnoi2014]世界树(虚树+DP)

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status] ...

  8. <虚树+树型DP> HNOI2014世界树

    <虚树+树型DP> HNOI2014世界树 #include <iostream> #include <cstdio> #include <cstring&g ...

  9. BZOJ3572:[HNOI2014]世界树——题解

    +++++++++++++++++++++++++++++++++++++++++++ +本文作者:luyouqi233. + +欢迎访问我的博客:http://www.cnblogs.com/luy ...

随机推荐

  1. Ruby基础教程 1-10

    类结构 1.数值类结构     Fixnum到Bignum会自动转换   2.常用数值表示   3. ans=10.divmod(3) ans[0]是商  ans[1]是余数   4.实例方法roun ...

  2. package.json中的devDependencies和dependencies有啥区别?

    如果你的项目是发布到npm的一个包, 那么这个包的package.json中的dependencies中的依赖是会被下载下来到这个包的node_modules文件夹中的(如果你的项目本身没有这个依赖) ...

  3. Linux命令应用大词典-第9章 数字计算

    9.1 bc:任意精度的计算器 9.2 dc:一个任意精度的计算器 9.3 expr:将表达式的值打印到标准输出 9.1 bc:任意精度的计算器 9.2 dc:一个任意精度的计算器 9.3 expr: ...

  4. 【C++模版之旅】项目中一次活用C++模板(traits)的经历 -新注解

    问题与需求: 请读者先看这篇文章,[C++模版之旅]项目中一次活用C++模板(traits)的经历. 对于此篇文章提出的问题,我给出一个新的思路. talking is cheap,show me t ...

  5. labview--http协议数据交互

    最近接了一个项目,需求是要将采集到的数据,以以下要求上报,并且提供接口供上层系统下发指令. 采用restful的http协议进行交互: 输入输出参数皆为json体. 响应包含三部分: Code:业务码 ...

  6. 利用爬虫、SMTP和树莓派3B发送邮件&续集&(爬取墨迹天气预报信息)

    -----------------------------------------------学无止境----------------------------------------------- 前 ...

  7. 【outPut_Class 输出类】使用说明

    对象:outPut 说明:定义输出结果类的相关操作.此对象的核心是[JSON]类,所以它继承了[JSON]类的所有方法 重要: 输出结果样式为XML时,自带根节点"root".输出 ...

  8. 【转】Buff机制及其实际运用

    转自 http://bbs.gameres.com/forum.php?mod=viewthread&tid=215027 首先我想说的是,这是一套机制,并不是单独的一个系统,所谓机制就是一种 ...

  9. numpy切片和布尔型索引

    numpy 标签(空格分隔): numpy 数据挖掘 切片 数组切片是原始数组的视图.这意味着数据不会被复制,视图上的任何修改都会直接反映到源数组上 In [16]: arr Out[16]: arr ...

  10. 利用人脸特征提取DeepID--解读世纪晟人脸识别

    概述:DeepID的目标是人脸验证(判断两张图片是否是一个人),同时衍生出人脸识别(多次人脸验证). DeepID采用增大数据集的方法: 增加新的数据,celebFaces(87628张图片,5436 ...