求助!(这题真的是名副其实的NOIP最难题啊)

P1600 [NOIP2016 提高组] 天天爱跑步

KokiNiwa @ 2019-05-31 21:53:23

#include <cstdio>
#include <vector>
#include <cstring>

using namespace std;

const int N = 3e5, Big = 6e5 + 10;              //一共有3e5个点

struct Node
{
    int v, nxt;
} edge[N<<1];
int head[N], tot;

void addedge(int u, int v)
{
    edge[++tot].v = v;
    edge[tot].nxt = head[u];
    head[u] = tot;
}

int n, m, w[N], s[N], t[N], lca[N], Snum[N];    //w[i]表示编号为i的点的观测时间 

void input()
{
    scanf("%d %d", &n, &m);
    for (int i = 1; i < n; ++i)
    {
        int u, v;
        scanf("%d %d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }
    for (int i = 1; i <= n; ++i)
        scanf("%d", &w[i]);
    for (int i = 1; i <= m; ++i)
    {
        scanf("%d %d", &s[i], &t[i]);
        ++Snum[s[i]];
    }
}

int fa[N][20], level[N];                        //编号为i的点的父亲为fa[i][0] 
                                                //fa[i][j]是节点i的2^j次方祖先 
void prepare(int u, int from)                   //u是从v过来的 
{
    level[u] = level[from] + 1;
    fa[u][0] = from;
    for (int i = 1; i <= 18; ++i)
        fa[u][i] = fa[fa[u][i-1]][i-1];
    for (int i = head[u]; i; i = edge[i].nxt)
    {
        int v = edge[i].v;
        if (v != from)
            prepare(v, u);
    }
}

void swap(int &u, int &v)
{
    int tmp = u;
    u = v;
    v = tmp;
}

int LCA(int u, int v)                           //倍增LCA 
{
    if (level[u] < level[v])
        swap(u, v);
    for (int i = 18; i >= 0; --i)
        if (level[fa[u][i]] >= level[v])
            u = fa[u][i];
    if (u == v)
        return u;
    for (int i = 18; i >= 0; --i)
        if (fa[u][i] != fa[v][i])
            u = fa[u][i], v = fa[v][i];
    return fa[u][0];
}

vector<int> putOff[N];                          //在一个结点i是LCA的时候,要去掉s[putOff[i]]里面所有数在桶里面的deep值 
vector<int> uToL[N];                            //从七点映射到lca 
vector<int> vToS[N];

void useLCA()
{
    for (int i = 1; i <= m; ++i)
    {
        lca[i] = LCA(s[i], t[i]);
        putOff[lca[i]].push_back(s[i]);
        uToL[s[i]].push_back(lca[i]);           //忘了初始化这个变量了 
        vToS[t[i]].push_back(2 * level[lca[i]] - level[s[i]]);
    }
}

int bucket[Big];

inline void addbucket(int val, int x)               //在哈希表里面加入一个值 
{
    bucket[val+n] += x;
}

inline int askbucket(int val)
{
    if (val + n < 0)
        return 0;
    return bucket[val+n];
}

int ans[N];

void dfs1(int u)
{
    int origin = askbucket(w[u] + level[u]);
    for (int i = head[u]; i; i = edge[i].nxt)
    {
        int v = edge[i].v;
        if (v != fa[u][0])
            dfs1(v);
    }
    addbucket(level[u], Snum[u]); 
    ans[u] += askbucket(w[u] + level[u]) - origin;
    int sze = putOff[u].size();
    for (int i = 0; i < sze; ++i)
        addbucket(level[putOff[u][i]], -1);
}

void cleanbucket()
{
    memset(bucket, 0, sizeof(bucket));
}

void dfs2(int u)
{
    int origin = askbucket(level[u] - w[u]);
    for (int i = head[u]; i; i = edge[i].nxt)
    {
        int v = edge[i].v;
        if (v != fa[u][0])
            dfs2(v);                                //这个函数我直接复制的dfs1,这里忘了改成dfs2()了 
    }
    int sze = vToS[u].size();
    for (int i = 0; i < sze; ++i)                   //由于只考虑某个节点的子树对某个点的贡献,所以我们要把这个循环放在上一个循环的后面 
        addbucket(vToS[u][i], 1);
    ans[u] += askbucket(level[u] - w[u]) - origin;  //刚才我这里写成了w[u] - level[u],时时刻刻想着算式的意义 
    sze = putOff[u].size();
    for (int i = 0; i < sze; ++i)
        addbucket(2 * level[u] - level[putOff[u][i]], -1);
}

void remove()
{
    for (int i = 1; i <= m; ++i)
        if (level[lca[i]] - level[s[i]] == w[lca[i]])
            --ans[lca[i]];
}

void output()
{
    for (int i = 1; i <= n; ++i)
        printf("%d ", ans[i]);
    printf("\n");
}

int main()
{
    input();
    prepare(1, 0);
    useLCA();
    dfs1(1);
    cleanbucket();
    dfs2(1);
    remove();
    output();
    return 0;
}
#1
AC
51ms/24248KB
#2
AC
194ms/42588KB
#3
AC
187ms/42632KB
#4
AC
198ms/42584KB
#5
AC
213ms/42980KB
#6
WA

#7
AC
186ms/42956KB
#8
WA

#9
WA

#10
WA

#11
WA

#12
AC
55ms/24288KB
#13
WA

#14
AC
53ms/24436KB
#15
AC
51ms/24476KB
#16
AC
54ms/24324KB
#17
AC
373ms/49288KB
#18
AC
318ms/49340KB
#19
WA

#20
AC
201ms/42492KB

情况大概就是这样。 有哪一位大佬能帮我调一下嘛?


by t162 @ 2019-05-31 21:54:37

Orz神仙无视黑题


by Kubic @ 2019-05-31 21:55:08

手动@Sai_0511 他说这道题是傻题


by SSerxhs @ 2019-05-31 21:56:58

列队保卫王国不知比这题高到哪里去了


by duyi @ 2019-05-31 21:59:46

列队保卫王国不知比这题高到哪里去了


by Qiuly @ 2019-05-31 22:35:11

保卫王国不是动态DP傻逼题吗....(逃


by Oakenshield @ 2019-05-31 22:39:49

这题和17、18年那几道题比起来可算是水题了


by jiuguaiwf @ 2019-05-31 22:42:53

正解考场都是不可做的,全局桶这个技巧反正我是做完这道题才会的。(说它简单或许是考场能用数据结构水不少分)


by Sai0511 @ 2019-05-31 22:47:15

@Kubic
啊?我啥时候说了?


by Kubic @ 2019-06-01 06:19:42

@Sai_0511 你在某老师课上说:“这是道线段树合并的傻题”


by Binary_Search_Tree @ 2019-11-07 11:12:56

列队保卫王国不知比这题高到哪里去了


| 下一页