[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】896 B. Ithea Plays With Chtholly
[题目]B. Ithea Plays With Chtholly [题意]交互题,有n格,每次给一个[1,c]的数字,回答填入的位置后再次给数字,要求在m轮内使n格填满且数列不递减.n,m>=2 ...
- 【BZOJ】1726 [Usaco2006 Nov]Roadblocks第二短路
[算法]最短路(spfa) 次短路 [题解] 正反跑两次SPFA,然后枚举每一条边,如果起点到一个端点的最短路+另一个端点到终点的最短路+长度 ≠ 最短路,则和答案比较,保存最小值. #include ...
- quick-cocos2dx 悬浮节点(NotificationNode)
cocos2dx 开发游戏时,有时某些节点不需要随着场景的切换而销毁.但cocos2dx的机制只允许同时只有一个运行的场景,如果你的所有节点都是依附于这个场景的,那场景的切换必然带来节点的销毁. 比如 ...
- 【洛谷 P4320】 道路相遇 (圆方树,LCA)
题目链接 题意:给一张无向图和\(M\)个询问,问\(u,v\)之间的路径的必经之点的个数. 对图建出圆方树,然后必经之点就是两点路径经过的原点个数,用\((dep[u]+dep[v]-dep[LCA ...
- python进行机器学习(二)之特征选择
毫无疑问,解决一个问题最重要的是恰当选取特征.甚至创造特征的能力,这叫做特征选取和特征工程.对于特征选取工作,我个人认为分为两个方面: 1)利用python中已有的算法进行特征选取. 2)人为分析各个 ...
- Python3 Socket和SocketServer 网络编程
socket只能实现同时一个服务和一个客户端实现交互,socketserver可以实现多个客户端同时和服务端交互 1.利用Socket编写简单的同一个端口容许多次会话的小案例: 服务端: #!/usr ...
- python实战===百度文字识别sdk
http://ai.baidu.com/docs#/OCR-Python-SDK/top
- 浅谈linux的死锁检测 【转】
转自:http://www.blog.chinaunix.net/uid-25942458-id-3823545.html 死锁:就是多个进程(≥2)因为争夺资源而相互等待的一种现象,若无外力推动,将 ...
- 关于c++的string的operator =
在 c++ primer 5 中在说到string的章节里面有这样一句话: string s5 = "hiya"; // copy initialization 也就是说,这里说上 ...
- 【bzoj2006】NOI2010超级钢琴
补了下前置技能…… 题意就是求一段区间的权值和前k大的子序列的和. 把段扔进优先队列 每次拿出来之后按照所选择的j进行分裂 #include<bits/stdc++.h> #define ...