天天爱跑步

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

我们首先考虑满足可以被观测到的条件。

为了方便,我们将一条路径分为两部分,一部分是往上的(包含LCA),另一部分是往下的(不包含LCA)。

对于第一部分,满足 \(d_u-d_x=w_x\rightarrow d_u=d_x+w_x\),是固有属性。

对于第二部分,满足 \(d_u-d_p+d_x-d_p=w_x\rightarrow w_x-d_x=d_u-2d_p\),也是固有属性。

又因为这个是有作用范围的,对于每个点记录一个类似于哈希表的东西,我们可以在路径上打个标记,说明这个位置有 \(d_u/d_u-2d_p\),然后查询哈希表中下标为 \(w_x\pm d_x\) 的值。

发现这是静态的,所以可以差分,对于一段 \((a,b)\)(对于第一二部分均适用),在 \(fa_a\) 上挂上一个下标处-1,\(b\) 处+1,就可以达到效果。

然后最后搜索子树权值和即可,累加遍历子树前后的差值即可(因为遍历后恰好增加了这个子树的贡献)。

这道题的差分很特别,需细细品味。

它记录的值虽然没有任何意义,但是利用的是差值计算答案。

#include<cstdio>
#include<iostream>
#include<cassert>
#include<cstring>
#include<vector>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while
typedef pair<int,int> pii;
#define x first
#define y second
const int N=300010,K=19,M=2*N;
int n,m,f[N][K],d[N],s[N*3],w[N],ans[N];
int h[N],e[M],ne[M],idx;//don't forget memset h!
vector<pii>g[N];
struct{
    int a,b,p;
}q[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x,int fa){
    d[x]=d[fa]+1;
    Ed{
        int j=e[i];
        if(j==fa)continue;
        f[j][0]=x;
        E(k, K-1)f[j][k]=f[f[j][k-1]][k-1];
        dfs(j,x);
    }
}
int lca(int a,int b){
    if(d[a]>d[b])swap(a,b);
    Re(i, K-1, 0)
        if(d[f[b][i]]>=d[a])b=f[b][i];
    if(a==b)return a;
    Re(i, K-1, 0)
        if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
    return f[a][0];
}
void calc(int x,int sg){
    int t=w[x]+sg*d[x]+M,lst=s[t];
    for(auto& it:g[x])s[it.x+M]+=it.y;//由于只是累加差值,这句话放哪里都行
    Ed{
        int j=e[i];
        if(j==f[x][0])continue;
        calc(j,sg);
    }
    // assert(!s[t]);
    ans[x]+=s[t]-lst;
}
void calc_up(){
    E(i, m){
        auto[a,b,p]=q[i];
        int D=d[a];
        g[a].push_back({D,1});
        g[f[p][0]].push_back({D,-1});
    }
    calc(1,1);
}
void calc_down(){
    E(i, n)g[i].clear();
    E(i, n*3)s[i]=0;
    E(i, m){
        auto[a,b,p]=q[i];
        int D=d[a]-2*d[p];
        g[b].push_back({D,1});
        g[p].push_back({D,-1});
    }
    calc(1,-1);
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    #endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    memset(h,-1,n*4+4);
    E(i, n-1){
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    dfs(1,0);
    E(i, n)cin>>w[i];
    E(i, m){
        int a,b;
        cin>>a>>b;
        // cout<<a<<' '<<b<<' '<<lca(a,b)<<'\n';
        q[i]={a,b,lca(a,b)};
    }
    calc_up();
    calc_down();
    E(i, n)cout<<ans[i]<<' ';
    return 0;
}
posted @ 2023-10-12 15:38  wscqwq  阅读(7)  评论(0编辑  收藏  举报