NOIP 天天爱跑步 [DFS/树链剖分][差分]

终于调完了,了了自己的一个心结。

并没有结束

暂时不写题解,下面的代码应该还有优化的空间,各种意义上

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
inline void read(int &res){
    static char ch;int flag=1;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
    while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
const int N = 300000;
int n,m,deep[N],sz[N],top[N],fa[N],son[N];
int w[N],tot,cnt,cun,depth,sum[N],T[N],Z[N<<1],ans[N];
vector<int> E[N],L[N],M[N],Y[N];
struct preson{
    int u,v,lca,len;
}P[N];
void dfsf(int u){
    sz[u]=1;
    for(int v,i=0;i<E[u].size();++i)
        if(v=E[u][i],v!=fa[u]){
            deep[v]=deep[u]+1;fa[v]=u;
            dfsf(v),sz[u]+=sz[v];
            if(sz[son[u]]<sz[v])son[u]=v;
        }
}
void dfss(int u,int f){
    top[u]=f;
    if(son[u])dfss(son[u],f);
    for(int v,i=0;i<E[u].size();++i)
        if(v=E[u][i],v!=fa[u]&&v!=son[u])dfss(v,v);
}
void dfst(int u){
    int dt=deep[u]+w[u],cmd;
    if(dt<=depth)cmd=T[dt];
    for(int v,i=0;i<E[u].size();++i)
        if(v=E[u][i],v!=fa[u])dfst(v);
    T[deep[u]]+=sum[u];if(dt<=depth)ans[u]=T[dt]-cmd;
    for(int i=0;i<L[u].size();++i)
        T[deep[L[u][i]]]--;
}
void dfsw(int u){
    int dt=deep[u]-w[u]+300000,cmd;
    cmd=Z[dt];
    for(int v,i=0;i<E[u].size();++i)
        if(v=E[u][i],v!=fa[u])dfsw(v);
    for(int i=0;i<M[u].size();++i)Z[300000+M[u][i]]++;
    ans[u]+=Z[dt]-cmd;
    for(int i=0;i<Y[u].size();++i)Z[300000+Y[u][i]]--;
}
int lca(int x,int y){
    while(top[x]!=top[y]){
        if(deep[top[x]]>deep[top[y]])swap(x,y);
        y=fa[top[y]];
    }
    return deep[x]<deep[y]?x:y;
}
int main(){
    read(n),read(m);
    for(int x,y,i=1;i<n;i++)
        read(x),read(y),E[x].push_back(y),E[y].push_back(x);
    deep[1]=1,dfsf(1),dfss(1,1);
    for(int i=1;i<=n;i++)read(w[i]),depth=max(depth,deep[i]);
    for(int i=1;i<=m;++i){
        read(P[i].u),read(P[i].v),sum[P[i].u]++;
        P[i].lca=lca(P[i].u,P[i].v),
        P[i].len=deep[P[i].u]+deep[P[i].v]-deep[P[i].lca]*2;
        L[P[i].lca].push_back(P[i].u);
    }
    dfst(1);
    for(int i=1;i<=m;i++)
        M[P[i].v].push_back(deep[P[i].v]-P[i].len),
        Y[P[i].lca].push_back(deep[P[i].v]-P[i].len);
    dfsw(1);
    for(int i=1;i<=m;i++)
        if(deep[P[i].u]-deep[P[i].lca]==w[P[i].lca])ans[P[i].lca]--;
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    return 0;
}

这里写图片描述
更新——更加优秀的代码。。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
inline void read(int &res){
    static char ch;int flag=1;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
    while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
const int N = 300000;
int n,m,deep[N],sz[N],top[N],fa[N],son[N],cnt1[N],cnt2[N],f1[N<<1],f2[N<<1];
int w[N],sum[N],T[N],Z[N<<1],ans[N];
vector<int> E[N],L[N],M[N];
void dfsf(int u){
    sz[u]=1;
    for(int v,i=0;i<E[u].size();++i)
        if(v=E[u][i],v!=fa[u]){
            deep[v]=deep[u]+1;fa[v]=u;
            dfsf(v),sz[u]+=sz[v];
            if(sz[son[u]]<sz[v])son[u]=v;
        }
}
void dfss(int u,int f){
    top[u]=f;
    if(son[u])dfss(son[u],f);
    for(int v,i=0;i<E[u].size();++i)
        if(v=E[u][i],v!=fa[u]&&v!=son[u])dfss(v,v);
}
void insert(int u){
    for(int i=0;i<L[u].size();i++)
    if (!M[u][i]){
        cnt1[f1[L[u][i]-deep[u]+N]]--;
        cnt2[f2[L[u][i]+deep[u]]]--;
    }
    else if (M[u][i]==1)cnt2[f2[L[u][i]]]++;
    else cnt1[f1[L[u][i]+N]]++;
}
void dfst(int x){
    int d1=w[x]-deep[x]+N,d2=w[x]+deep[x],y=f1[d1],z=f2[d2];
    f1[d1]=f2[d2]=x;
    for(int i=0;i<E[x].size();++i)
        if(E[x][i]!=fa[x])dfst(E[x][i]);
    insert(x);
    ans[x]+=cnt1[x]+cnt2[x];
    cnt1[y]+=cnt1[x],cnt2[z]+=cnt2[x];
    f1[d1]=y;f2[d2]=z;
}
int lca(int x,int y){
    while(top[x]!=top[y]){
        if(deep[top[x]]>deep[top[y]])swap(x,y);
        y=fa[top[y]];
    }
    return deep[x]<deep[y]?x:y;
}
int main(){
    read(n),read(m);
    for(int x,y,i=1;i<n;i++)
        read(x),read(y),E[x].push_back(y),E[y].push_back(x);
    deep[1]=1,fa[1]=1,dfsf(1),dfss(1,1);
    for(int i=1;i<=n;i++)read(w[i]);
    for(int u,v,c,i=1;i<=m;++i){
        read(u),read(v),c=lca(u,v);
        if(deep[u]-deep[c]==w[c])ans[c]++;
        L[c].push_back(deep[u]-deep[c]),M[c].push_back(0);
        L[u].push_back(deep[u]),M[u].push_back(1);
        L[v].push_back((deep[u]-2*deep[c])),M[v].push_back(-1);
    }
    dfst(1);
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    return 0;
}

这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值