• 天天爱跑步


    传送门

    终于拿下NOIP最难一题

    看别人的题解看不懂

    于是准备写一篇更通俗易懂杂乱无章的题解

    解法:

    树上差分+线段树(桶)+LCA

    将每条路径在LCA处切成上升路径和下降路径

    会发现对于x号观察员若观察到玩家i

    则必有
    dep[i]=w[x]+depx

    dep[i]-2*dep[lca]=w[x]-depx

    我们用桶标记(桶用动态开点线段树实现)

    具体实现:
    用两种线段树统计 第一种统计上升段 第二种统计下降段

    若一个玩家从s到t点 记L=LCA(s,t)
    则在s节点加上上升段该值标记(dep[s])
    在t节点加上下降段该值标记(dep[s]-2dep[L])
    则为了避免在L处统计两次
    下降段在L处删除上述标记(dep[s]-2
    dep[L])
    上升段在L的父亲处删除上述标记(dep[s])

    然后一遍dfs
    对于每个点x
    将其子节点的线段树都合并起来
    并加上/删去该点的标记值
    对于上升段的线段树
    求w[i]-dep[x]的次数
    对于下降段的线段树
    求w[i]+dep[x]的次数

    最后x点答案即为上面两次求的答案之和

    总复杂度 O((nlog n))

    代码:

    200行代码 还好没出祸。。。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<map>
    #define inf 2000000000
    #define min(x,y) ((x)<(y)?(x):(y))
    #define max(x,y) ((x)>(y)?(x):(y))
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define dwn(i,a,b) for(int i=(a);i>=(b);--i)
    using namespace std;
    typedef long long ll;
    int n,m,root=1,a[300010];
    int dep[300010],f[300010][20],lg2[300010];
    int tot=1,head[300010];
    queue<int> que;
    int tot1=0,rt1[300010],up[6000010],ul[6000010],ur[6000010];
    int tot2=0,rt2[300010],dn[6000010],dl[6000010],dr[6000010];
    vector<int> add1[300010],add2[300010],del1[300010],del2[300010];
    int ans[300010];
    struct EDGE
    {
        int nxt,to;
    }edge[600010];
    void adde(int u,int v)
    {
        edge[++tot].nxt=head[u];
        edge[tot].to=v;
        head[u]=tot;
    }
    int read()
    {
        int x=0;
        char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9')
        {
            x=(x<<3)+(x<<1)+(ch^48);
            ch=getchar();
        }
        return x;
    }
    void bfs()
    {
        dep[root]=1;
        que.push(root);
        while(!que.empty())
        {
            int x=que.front();que.pop();
            for(int i=head[x];i;i=edge[i].nxt)
            {
                int y=edge[i].to;
                if(dep[y]) continue;
                dep[y]=dep[x]+1;
                f[y][0]=x;
                rep(i,1,lg2[dep[y]])
                {
                    f[y][i]=f[f[y][i-1]][i-1];
                }
                que.push(y);
            }
        }
    }
    int lca(int x,int y)
    {
        if(dep[x]>dep[y]) swap(x,y);
        dwn(i,lg2[dep[y]-dep[x]],0)
            if(dep[f[y][i]]>=dep[x]) y=f[y][i];
        if(x==y) return x;
        dwn(i,lg2[dep[x]],0)
            if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    void adup(int &k,int l,int r,int x,int d)
    {
        if(!k) k=++tot1;
        if(l==r)
        {
            up[k]+=d;
            return;
        }
        int mid=(l+r)>>1;
        if(x<=mid) adup(ul[k],l,mid,x,d);
        else adup(ur[k],mid+1,r,x,d);
        up[k]=up[ul[k]]+up[ur[k]];
    }
    void addn(int &k,int l,int r,int x,int d)
    {
        if(!k) k=++tot2;
        if(l==r)
        {
            dn[k]+=d;
            return;
        }
        int mid=(l+r)>>1;
        if(x<=mid) addn(dl[k],l,mid,x,d);
        else addn(dr[k],mid+1,r,x,d);
        dn[k]=dn[dl[k]]+dn[dr[k]];
    }
    int askup(int &k,int l,int r,int x)
    {
        if(!k) return 0;
        if(l==r)
        {
            return up[k];
        }
        int mid=(l+r)>>1;
        if(x<=mid) return askup(ul[k],l,mid,x);
        else return askup(ur[k],mid+1,r,x);
    }
    int askdn(int &k,int l,int r,int x)
    {
        if(!k) return 0;
        if(l==r)
        {
            return dn[k];
        }
        int mid=(l+r)>>1;
        if(x<=mid) return askdn(dl[k],l,mid,x);
        else return askdn(dr[k],mid+1,r,x);
    }
    int mergeup(int p,int q,int l,int r)
    {
        if(!p) return q;
        if(!q) return p;
        if(l==r)
        {
            up[p]+=up[q];
            return p;
        }
        int mid=(l+r)>>1;
        ul[p]=mergeup(ul[p],ul[q],l,mid);
        ur[p]=mergeup(ur[p],ur[q],mid+1,r);
        up[p]=up[ul[p]]+up[ur[p]];
        return p;
    }
    int mergedn(int p,int q,int l,int r)
    {
        if(!p) return q;
        if(!q) return p;
        if(l==r)
        {
            dn[p]+=dn[q];
            return p;
        }
        int mid=(l+r)>>1;
        dl[p]=mergedn(dl[p],dl[q],l,mid);
        dr[p]=mergedn(dr[p],dr[q],mid+1,r);
        dn[p]=dn[dl[p]]+dn[dr[p]];
        return p;
    }
    void dfs(int x)
    {
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int y=edge[i].to;
            if(y==f[x][0]) continue;
            dfs(y);
            rt1[x]=mergeup(rt1[x],rt1[y],1,2*n);
            rt2[x]=mergedn(rt2[x],rt2[y],1,2*n);
        }
        for(int i=0;i<add1[x].size();++i)
            adup(rt1[x],1,2*n,add1[x][i],1);
        for(int i=0;i<add2[x].size();++i)
            addn(rt2[x],1,2*n,add2[x][i],1);
        for(int i=0;i<del1[x].size();++i)
            adup(rt1[x],1,2*n,del1[x][i],-1);
        for(int i=0;i<del2[x].size();++i)
            addn(rt2[x],1,2*n,del2[x][i],-1);
        ans[x]+=askup(rt1[x],1,2*n,a[x]+dep[x]);
        ans[x]+=askdn(rt2[x],1,2*n,a[x]-dep[x]+n);
    }
    int main()
    {
        n=read(),m=read();
        rep(i,2,n) lg2[i]=lg2[i>>1]+1;
        rep(i,1,n-1)
        {
            int u=read(),v=read();
            adde(u,v),adde(v,u);
        }
        rep(i,1,n) a[i]=read();
        bfs();
        rep(i,1,m)
        {
            int s=read(),t=read();
            int l=lca(s,t);
            add1[s].push_back(dep[s]);
            add2[t].push_back(dep[s]-2*dep[l]+n);
            del1[f[l][0]].push_back(dep[s]);
            del2[l].push_back(dep[s]-2*dep[l]+n);
        }
        dfs(root);
        rep(i,1,n)
        {
            printf("%d ",ans[i]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    Dapper的常用操作
    git下载慢的解决方案
    笔记
    第06组 Beta冲刺(3/5)
    第06组 Beta冲刺(2/5)
    第06组 Beta冲刺(1/5)
    第06组 Alpha事后诸葛亮
    第06组 Alpha冲刺(6/6)
    第06组 Alpha冲刺(5/6)
    第06组 Alpha冲刺(4/6)
  • 原文地址:https://www.cnblogs.com/MYsBlogs/p/11169541.html
Copyright © 2020-2023  润新知