[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 }

 

转载于:https://www.cnblogs.com/HocRiser/p/9774554.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值