【NOIp2016】天天爱跑步

题面

https://www.luogu.org/problem/P1600

题解

树链剖分$+$对每条重链分治$+$桶。

注意:树链剖分求$LCA$,跳矮(重链顶端的高矮)返高。

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ri register int
#define N 300000
using namespace std;

inline int read() {
    int ret=0,f=0;char ch=getchar();
    while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
    while (ch>='0' && ch<='9') ret*=10,ret+=ch-'0',ch=getchar();
    return f?-ret:ret;
}

int siz[N],top[N],p[N],cnt,dep[N],fa[N],ans[N];
vector<int> to[N];
int n,m,w[N];

void dfs_1(int x,int ff) {
    fa[x]=ff; dep[x]=dep[ff]+1;
    siz[x]=1;
    for (ri i=0;i<to[x].size();i++) {
        int y=to[x][i]; if (y==ff) continue;
        dfs_1(y,x);
        siz[x]+=siz[y];
    }
}

void dfs_2(int x,int ff,int ctop) {
    int md=0,hs=-1;
    p[x]=++cnt; top[x]=ctop;
    for (ri i=0;i<to[x].size();i++) {
        int y=to[x][i]; if (y==ff) continue;
        if (siz[y]>md) md=siz[y],hs=y;
    }
    if (hs!=-1) dfs_2(hs,x,ctop);
    for (ri i=0;i<to[x].size();i++) {
        int y=to[x][i]; if (y==ff || y==hs) continue;
        dfs_2(y,x,y);
    }
}

int lca(int x,int y) {
    while (top[x]^top[y]) {
        if (dep[top[x]]>dep[top[y]]) x=fa[top[x]]; else y=fa[top[y]];
    }
    if (dep[x]<dep[y]) return x; else return y;
}

struct node {
    int v,p,top,id;
    bool operator < (const node &rhs) const {
      if (top!=rhs.top) return top<rhs.top;
      if (v!=rhs.v) return v<rhs.v;
      if (p!=rhs.p) return p<rhs.p;
      return 0;
    }
} up[N],dw[N];

int sup[N],sdw[N];

void count_up(int t,int lp,int rp,int v) {
    int a=lower_bound(up+1,up+n+1,(node){v,lp,t,-1})-up;
    int b=upper_bound(up+1,up+n+1,(node){v,rp,t,-1})-up;
    sup[a]++; sup[b]--;
}

void count_dw(int t,int lp,int rp,int v) {
    int a=lower_bound(dw+1,dw+n+1,(node){v,lp,t,-1})-dw;
    int b=upper_bound(dw+1,dw+n+1,(node){v,rp,t,-1})-dw;
    sdw[a]++; sdw[b]--;
}

int main() {
    
    n=read(); m=read();
    for (ri i=1;i<n;i++) {
        int u=read(),v=read();
        to[u].push_back(v);
        to[v].push_back(u);
    }
    dfs_1(1,0);
    dfs_2(1,0,1);
    for (ri i=1;i<=n;i++) w[i]=read();
    for (ri i=1;i<=n;i++) {
        up[p[i]]=(node){dep[i]+w[i],p[i],top[i],i};
        dw[p[i]]=(node){dep[i]-w[i],p[i],top[i],i};
    }
    
    sort(up+1,up+n+1);
    sort(dw+1,dw+n+1);
    
    for (ri i=1;i<=m;i++) {
        int s=read(),t=read();
        int x=lca(s,t);
        int vid=dep[s],vid2=dep[t]-(dep[s]+dep[t]-2*dep[x]);
        while (1) {
            if (dep[top[s]]>dep[x]) count_up(top[s],p[top[s]],p[s],vid),s=fa[top[s]];
            else {count_up(top[s],p[x],p[s],vid); break;}
        }
        while (1) {
            if (dep[top[t]]>dep[x]+1) count_dw(top[t],p[top[t]],p[t],vid2),t=fa[top[t]];
            else {count_dw(top[t],p[t]-(dep[t]-(dep[x]+1)),p[t],vid2); break;}
        }
    }
    
    for (ri i=1;i<=n;i++) {
        sup[i]+=sup[i-1]; ans[up[i].id]+=sup[i];
        sdw[i]+=sdw[i-1]; ans[dw[i].id]+=sdw[i];
    }
    
    for (ri i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}
posted @ 2019-11-09 16:07  HellPix  阅读(129)  评论(0编辑  收藏  举报