[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 ...
随机推荐
- Quick-Cocos2dx-Community_3.6.3_Release 编译时libtiff.lib 无法解析
Quick-Cocos2dx-Community_3.6.3_Release 使用VS2012编译,报错: libtiff.lib lnk2001 无法解析的外部符号 ltod3 类似于上面这种,刚才 ...
- python初步学习-python运算符
算数运算符 操作 描述 例子 + 加法-对操作符的两侧增加值 a+b=30 - 减法 a-b=30 * 乘法 a * b = 30 / 除法 a/b=30 % 模(取余) a%b=30 ** 指数(幂 ...
- Java 中的成员内部类
内部类中最常见的就是成员内部类,也称为普通内部类.我们来看如下代码: 运行结果为: 从上面的代码中我们可以看到,成员内部类的使用方法: 1. Inner 类定义在 Outer 类的内部,相当于 Out ...
- bzoj 1854 游戏 二分图匹配 || 并查集
题目链接 Description lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备时,他只能使用该装备的 ...
- perl HTML::HeadParser获取html头部信息
use LWP::Simple; use HTML::HeadParser; use utf8; binmode(STDOUT, ":encoding(gbk)"); #设置win ...
- 数据库===轻量级mysql数据库管理工具
已经上传至: https://download.csdn.net/download/bo_mask/10276952
- webapi-2 接口参数
1. 实例 using System; using System.Collections.Generic; using System.Linq; using System.Net; using Sys ...
- mybatis开启字段自动映射为java驼峰命名规则
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> & ...
- FineReport——JS二次开发(分页预览)
BS访问某个cpt模板,报表servlet将会将cpt文件解析成对应的html,报表内容最终转换为一个table,位于id=content-container的div中. 在模板和html页面中,他们 ...
- ASP .NET CORE 部署linux 系统上的所需要的sdk 使用链接
https://www.microsoft.com/net/learn/get-started/linuxopensuse