zoukankan      html  css  js  c++  java
  • [NOIP2016]天天爱跑步(树上差分+线段树合并)

    将每个人跑步的路径拆分成x->lca,lca->y两条路径分别考虑:

    对于在点i的观察点,这个人(s->t)能被观察到的充要条件为:

    1.直向上的路径:w[i]=dep[s]-dep[i],移项得w[i]+dep[i]=dep[s]

    2.直向下的路径:w[i]=dep[s]-dep[lca]+dep[i]-dep[lca],移项得w[i]-dep[i]=dep[s]-2*dep[lca]。

    问题转化为,对每个点i,统计它的子树中有多少个点x满足dep[x]=w[i]+dep[i]或dep[x]-2*dep[lca]=w[i]-dep[i],这是经典的线段树合并问题。

    注意到并不是子树中所有满足条件的点都能被统计,因为有的点还没到观察点就往下跑了(lca深度大于当前观察点),差分解决。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #define lson ls[x],L,mid
     6 #define rson rs[x],mid+1,R
     7 #define rep(i,l,r) for (int i=l; i<=r; i++)
     8 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     9 typedef long long ll;
    10 using namespace std;
    11 
    12 const int N=300010,M=10000010;
    13 int n,m,u,v,cnt,s,t,w[N],d[N],ans[N],fa[N][20],h[N],nxt[N<<1],to[N<<1];
    14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    15 
    16 struct T{
    17     int nd,v[M],ls[M],rs[M],rt[N];
    18     void ins(int &x,int L,int R,int pos,int k){
    19         if (!x) x=++nd;
    20         if (L==R){ v[x]+=k; return; }
    21         int mid=(L+R)>>1;
    22         if (pos<=mid) ins(lson,pos,k); else ins(rson,pos,k);
    23     }
    24 
    25     int merge(int x,int y,int L,int R){
    26         if (!x || !y) return x+y;
    27         if (L==R) { v[x]+=v[y]; return x; }
    28         int mid=(L+R)>>1;
    29         ls[x]=merge(ls[x],ls[y],L,mid);
    30         rs[x]=merge(rs[x],rs[y],mid+1,R);
    31         return x;
    32     }
    33 
    34     int que(int x,int L,int R,int pos){
    35         if (!x) return 0;
    36         if (L==R) return v[x];
    37         int mid=(L+R)>>1;
    38         if (pos<=mid) return que(lson,pos); else return que(rson,pos);
    39     }
    40 }T1,T2;
    41 
    42 void dfs(int x){
    43     rep(i,1,19) fa[x][i]=fa[fa[x][i-1]][i-1];
    44     For(i,x) if ((k=to[i])!=fa[x][0]) fa[k][0]=x,d[k]=d[x]+1,dfs(k);
    45 }
    46 
    47 void dfs2(int x){
    48     For(i,x) if ((k=to[i])!=fa[x][0]){
    49         dfs2(k);
    50         T1.rt[x]=T1.merge(T1.rt[x],T1.rt[k],0,n);
    51         T2.rt[x]=T2.merge(T2.rt[x],T2.rt[k],0,2*n);
    52     }
    53     ans[x]+=(w[x]+d[x]>=0 && w[x]+d[x]<=n) ? T1.que(T1.rt[x],0,n,w[x]+d[x]) : 0;
    54     ans[x]+=(w[x]-d[x]>=-n && w[x]-d[x]<=n) ? T2.que(T2.rt[x],0,2*n,w[x]-d[x]+n) : 0;
    55 }
    56 
    57 int Lca(int x,int y){
    58     if (d[x]<d[y]) swap(x,y);
    59     int t=d[x]-d[y];
    60     for (int i=19; ~i; i--) if (t&(1<<i)) x=fa[x][i];
    61     if (x==y) return x;
    62     for (int i=19; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    63     return fa[x][0];
    64 }
    65 
    66 int main(){
    67     freopen("running.in","r",stdin);
    68     freopen("running.out","w",stdout);
    69     scanf("%d%d",&n,&m);
    70     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
    71     rep(i,1,n) scanf("%d",&w[i]);
    72     dfs(1);
    73     rep(i,1,m){
    74         scanf("%d%d",&s,&t); int lca=Lca(s,t);
    75         T1.ins(T1.rt[s],0,n,d[s],1); T1.ins(T1.rt[fa[lca][0]],0,n,d[s],-1);
    76         T2.ins(T2.rt[t],0,2*n,d[s]-2*d[lca]+n,1);
    77         T2.ins(T2.rt[fa[lca][0]],0,2*n,d[s]-2*d[lca]+n,-1);
    78         if (d[s]-d[lca]==w[lca]) ans[lca]--;
    79     }
    80     dfs2(1);
    81     rep(i,1,n) printf("%d ",ans[i]); puts("");
    82     return 0;
    83 }
  • 相关阅读:
    CSS团队协作规范
    百度前端学院-基础学院-第四课
    百度前端学院-基础学院-第三课
    百度前端学院-基础学院-第二课
    vue(三)-父子组件通信
    setTimeout()与clearTimeout()
    vue(二)-父子组件语法
    vue(一)使用vue-cli搭建项目
    CSS table-layout 属性
    git学习
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9774554.html
Copyright © 2011-2022 走看看