[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深度大于当前观察点),差分解决。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson ls[x],L,mid
#define rson rs[x],mid+1,R
#define rep(i,l,r) for (int i=l; i<=r; i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
typedef long long ll;
using namespace std; const int N=,M=;
int n,m,u,v,cnt,s,t,w[N],d[N],ans[N],fa[N][],h[N],nxt[N<<],to[N<<];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } struct T{
int nd,v[M],ls[M],rs[M],rt[N];
void ins(int &x,int L,int R,int pos,int k){
if (!x) x=++nd;
if (L==R){ v[x]+=k; return; }
int mid=(L+R)>>;
if (pos<=mid) ins(lson,pos,k); else ins(rson,pos,k);
} int merge(int x,int y,int L,int R){
if (!x || !y) return x+y;
if (L==R) { v[x]+=v[y]; return x; }
int mid=(L+R)>>;
ls[x]=merge(ls[x],ls[y],L,mid);
rs[x]=merge(rs[x],rs[y],mid+,R);
return x;
} int que(int x,int L,int R,int pos){
if (!x) return ;
if (L==R) return v[x];
int mid=(L+R)>>;
if (pos<=mid) return que(lson,pos); else return que(rson,pos);
}
}T1,T2; void dfs(int x){
rep(i,,) fa[x][i]=fa[fa[x][i-]][i-];
For(i,x) if ((k=to[i])!=fa[x][]) fa[k][]=x,d[k]=d[x]+,dfs(k);
} void dfs2(int x){
For(i,x) if ((k=to[i])!=fa[x][]){
dfs2(k);
T1.rt[x]=T1.merge(T1.rt[x],T1.rt[k],,n);
T2.rt[x]=T2.merge(T2.rt[x],T2.rt[k],,*n);
}
ans[x]+=(w[x]+d[x]>= && w[x]+d[x]<=n) ? T1.que(T1.rt[x],,n,w[x]+d[x]) : ;
ans[x]+=(w[x]-d[x]>=-n && w[x]-d[x]<=n) ? T2.que(T2.rt[x],,*n,w[x]-d[x]+n) : ;
} int Lca(int x,int y){
if (d[x]<d[y]) swap(x,y);
int t=d[x]-d[y];
for (int i=; ~i; i--) if (t&(<<i)) x=fa[x][i];
if (x==y) return x;
for (int i=; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][];
} int main(){
freopen("running.in","r",stdin);
freopen("running.out","w",stdout);
scanf("%d%d",&n,&m);
rep(i,,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
rep(i,,n) scanf("%d",&w[i]);
dfs();
rep(i,,m){
scanf("%d%d",&s,&t); int lca=Lca(s,t);
T1.ins(T1.rt[s],,n,d[s],); T1.ins(T1.rt[fa[lca][]],,n,d[s],-);
T2.ins(T2.rt[t],,*n,d[s]-*d[lca]+n,);
T2.ins(T2.rt[fa[lca][]],,*n,d[s]-*d[lca]+n,-);
if (d[s]-d[lca]==w[lca]) ans[lca]--;
}
dfs2();
rep(i,,n) printf("%d ",ans[i]); puts("");
return ;
}
[NOIP2016]天天爱跑步(树上差分+线段树合并)的更多相关文章
- 【bzoj4719】[Noip2016]天天爱跑步 权值线段树合并
题目描述 给出一棵n个点的树,以及m次操作,每次操作从起点向终点以每秒一条边的速度移动(初始时刻为0),最后对于每个点询问有多少次操作在经过该点的时刻为某值. 输入 第一行有两个整数N和M .其中N代 ...
- [Luogu5327][ZJOI2019]语言(树上差分+线段树合并)
首先可以想到对每个点统计出所有经过它的链的并所包含的点数,然后可以直接得到答案.根据实现不同有下面几种方法.三个log:假如对每个点都存下经过它的链并S[x],那么每新加一条路径进来的时候,相当于在路 ...
- [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)
[BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...
- LOJ #2359. 「NOIP2016」天天爱跑步(倍增+线段树合并)
题意 LOJ #2359. 「NOIP2016」天天爱跑步 题解 考虑把一个玩家的路径 \((x, y)\) 拆成两条,一条是 \(x\) 到 \(lca\) ( \(x, y\) 最近公共祖先) 的 ...
- 2018.08.28 洛谷P4556 [Vani有约会]雨天的尾巴(树上差分+线段树合并)
传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...
- bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】
这居然是我第一次写线段树合并--所以我居然在合并的时候加点结果WAWAWAMLEMLEMLE--!ro的时候居然直接指到la就行-- 树上差分,每个点建一棵动态开点线段树,然后统计答案的时候合并即可 ...
- BZOJ 3307 雨天的尾巴 (树上差分+线段树合并)
题目大意:给你一棵树,树上一共n个节点,共m次操作,每次操作给一条链上的所有节点分配一个权值,求所有节点被分配到所有的权值里,出现次数最多的权值是多少,如果出现次数相同就输出最小的. (我辣鸡bzoj ...
- Luogu5327 ZJOI2019语言(树上差分+线段树合并)
暴力树剖做法显然,即使做到两个log也不那么优美. 考虑避免树剖做到一个log.那么容易想到树上差分,也即要对每个点统计所有经过他的路径产生的总贡献(显然就是所有这些路径端点所构成的斯坦纳树大小),并 ...
- P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)
显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...
随机推荐
- 【CodeForces】788E New task
[题意]n个数,每个数有附加属性0或1,初始全为1.m个操作,每个操作可以改变一个数字的属性为0或1.对于每次操作后的序列求有多少子序列满足要求:5个数字,中间3个数相等且属性为1,左右两个数小于等于 ...
- auto-keras 测试保存导入模型
# coding:utf-8 import time import matplotlib.pyplot as plt from autokeras import ImageClassifier# 保存 ...
- hdfs文件上传机制与namenode元数据管理机制
1.hdfs文件上传机制 文件上传过程: 1.客户端想NameNode申请上传文件, 2.NameNode返回此次上传的分配DataNode情况给客户端 3.客户端开始依向dataName上传对应 ...
- Python模块学习 - Fileinput
Fileinput模块 fileinput是python提供的标准库,使用fileinput模块可以依次读取命令行参数中给出的多个文件.也就是说,它可以遍历 sys.argv[1:],并按行读取列表中 ...
- Linux C中内联汇编的语法格式及使用方法(Inline Assembly in Linux C)【转】
转自:http://www.linuxidc.com/Linux/2013-06/85221p3.htm 阅读Linux内核源码或对代码做性能优化时,经常会有在C语言中嵌入一段汇编代码的需求,这种嵌入 ...
- 动画基础--基于Core Animation(2)
参考:https://zsisme.gitbooks.io/ios-/content/ 前面的文章动画基础--基于Core Animation(1)提到了图层的基本概念以及可动画参数几何学等知识. 本 ...
- JDBC数据源连接池(2)---C3P0
我们接着<JDBC数据源连接池(1)---DBCP>继续介绍数据源连接池. 首先,在Web项目的WebContent--->WEB-INF--->lib文件夹中添加C3P0的j ...
- 【转】Jmeter-----函数引用和函数重定向
详见内文
- Linux下安装PHP环境(非集成)
一.安装Apache1.到官网下载 http://httpd.apache.org/download.cgi 2.安装apache [root@localhost 52lamp]# mkdir ...
- 前端读者 | 百度前端编码规范(JS)
本文来自:百度FEX 1 前言 JavaScript在百度一直有着广泛的应用,特别是在浏览器端的行为管理.本文档的目标是使JavaScript代码风格保持一致,容易被理解和被维护. 虽然本文档是针对J ...