BZOJ 4719 [Noip2016]天天爱跑步 ——树链剖分

Posted SfailSth ——Salt Fish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 4719 [Noip2016]天天爱跑步 ——树链剖分相关的知识,希望对你有一定的参考价值。

一直以为自己当时是TLE了,但是再看发现居然WA?

然后把数组扩大一倍,就A掉了。QaQ

没什么好说的。一段路径分成两段考虑,上升的一段深度+时间是定值,下降的一段深度-时间是定值,然后打标记统计即可。

发现大概是统计数组因为深度+时间太大炸掉了。

现在想想,当时没有对拍,真是后怕。

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int read()
{
    int ret=0,f=1; char ch=getchar();
    while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
    while (ch>=‘0‘&&ch<=‘9‘){ret*=10;ret+=ch-‘0‘;ch=getchar();}
    return ret*f;
}
int n,m;
int h[600005],to[600002],ne[600002],en=0;
void add(int a,int b)
{
    to[en]=b;
    ne[en]=h[a];
    h[a]=en++;
}
int root=1,dep[600005],fa[600005],son[600005],siz[600005];
vector <int> st[600005];
vector <int> ed[600005];
void dfs1(int k)
{
    siz[k]=1;
    for (int i=h[k];i>=0;i=ne[i])
    if (to[i]!=fa[k]){
        fa[to[i]]=k;
        dep[to[i]]=dep[k]+1;
        dfs1(to[i]);
        siz[k]+=siz[to[i]];
        if (siz[son[k]]<siz[to[i]]) son[k]=to[i];
    }
}
int pos[600005],top[600005],li[600005],cnt=0;
void dfs2(int k,int tp)
{
    top[k]=tp;
    cnt++; pos[k]=cnt; li[cnt]=k;
    if (!son[k]) return ;
    if (son[k]) dfs2(son[k],tp);
    for (int i=h[k];i>=0;i=ne[i])
    if (to[i]!=son[k]&&to[i]!=fa[k]) dfs2(to[i],to[i]);
    return ;
}
int w[600005];
vector <int> que[600005];
vector <int> bel[600005];
struct node{int s,t,lca;}q[600005];
int vis[600005],f[600005];
int gf(int k)
{
    if (f[k]==k) return k;
    else return f[k]=gf(f[k]);
}
void dfs3(int k)
{
    f[k]=k;
    vis[k]=1;
    for (int i=0;i<que[k].size();++i)
        if (vis[que[k][i]]) q[bel[k][i]].lca=gf(que[k][i]);
    for (int i=h[k];i>=0;i=ne[i])
    if (fa[k]!=to[i]){
        dfs3(to[i]);
        f[to[i]]=k;
    }
    return ;
}
void lca(){dfs3(1);}
int s[600005],ans[600005];
void add(int a,int b,int fn)
{
    if (dep[a]<dep[b]) swap(a,b);
    while (top[a]!=top[b])
    {
        if (dep[top[a]]<dep[top[b]]) swap(a,b);
        st[pos[top[a]]].push_back(fn);
        ed[pos[a]+1].push_back(fn);
        a=fa[top[a]];
    }
    if (dep[a]<dep[b]) swap(a,b);
    st[pos[b]].push_back(fn);
    ed[pos[a]+1].push_back(fn);
}
void cal1()
{
    for (int i=1;i<=n;++i) w[i]-=dep[i];
    for (int i=1;i<=m;++i)
    {
        int at;
        at=dep[q[i].s]-dep[q[i].lca];
        if (w[q[i].lca]==at-dep[q[i].lca]) ans[q[i].lca]--;
        add(q[i].lca,q[i].t,at-dep[q[i].lca]);
    }
    for (int i=1;i<=n;++i)
    {
        for (int j=0;j<st[i].size();++j) s[st[i][j]]++;
        for (int j=0;j<ed[i].size();++j) s[ed[i][j]]--;
        ans[li[i]]+=s[w[li[i]]];
    }
}
void cal2()
{
    for (int i=0;i<=n+5;++i) st[i].clear(),ed[i].clear();
    memset(s,0,sizeof s);
    for (int i=1;i<=n;++i) w[i]+=2*dep[i];
    for (int i=1;i<=m;++i)
    {
        int at;
        at=dep[q[i].s]-dep[q[i].lca];
        add(q[i].lca,q[i].s,at+dep[q[i].lca]);
    }
    for (int i=1;i<=n;++i)
    {
        for (int j=0;j<st[i].size();++j) s[st[i][j]]++;
        for (int j=0;j<ed[i].size();++j) s[ed[i][j]]--;
        ans[li[i]]+=s[w[li[i]]];
    }
}
void out()
{
    for (int i=1;i<n;++i)printf("%d ",ans[i]); printf("%d",ans[n]);
}
int main()
{
    memset(h,-1,sizeof h);
    n=read(); m=read();
    for (int i=1;i<n;++i)
    {
        int a,b;
        a=read(); b=read();
        add(a,b); add(b,a);
    }
    for (int i=1;i<=n;++i)
        w[i]=read();
    for (int i=1;i<=m;++i)
    {
        int a,b;
        a=read(); b=read();
        que[a].push_back(b);
        que[b].push_back(a);
        bel[a].push_back(i);
        bel[b].push_back(i);
        q[i].s=a;q[i].t=b;
    }
    dfs1(root);
    dfs2(root,root);
    lca();
    cal1();
    cal2();
    out();
    return 0;
}

  

以上是关于BZOJ 4719 [Noip2016]天天爱跑步 ——树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4719: [Noip2016]天天爱跑步 树上差分

BZOJ 4719 [Noip2016]天天爱跑步 ——树链剖分

BZOJ 4719--天天爱跑步(LCA&差分)

NOIP2016天天爱跑步

Noip 2016 天天爱跑步 题解

天天爱跑步[NOIP2016]