文章目录
- 题目
- 思路
- 代码
题目
Luogu
题目大意
一棵树,nnn 个节点,每个点有观察员, 观察员 iii 在 wiw_iwi? 观察一次,有 mmm 个人跑步,第 iii 个人从 sis_isi? 到 tit_iti? ,到达后下一秒消失, mmm 个人同时出发,边长均为 111,问每个观察员观察的人数?
1≤n,m≤3?1051\le n,m\le 3\cdot10^51≤n,m≤3?105
思路
看着表来打
25opt:25\ opt:25 opt:
考虑一些比较暴力的做法
预处理出每个人走的路径然后一秒一秒走,观察员按照时间排序,被观察到暴力加++
时间复杂度 O(n(n+m))O(n(n+m))O(n(n+m))
6?206\sim206?20 发现暴力++的方法已经不行了,这就提示我们要用一些比较快的加法
差分,前缀和,线段树
15opt:15\ opt:15 opt: 链
6?86\sim 86?8 我们可以这样做
在所有 sis_isi? 处分往左右走++
把跑步的人看作 (ti?si+1,si,l∣r)(t_i-s_i+1,s_i,l|r)(ti??si?+1,si?,l∣r) 的修改点
观察者看作 (wi,i,0)(w_i,i,0)(wi?,i,0) 的询问点
两个弄在一起按时间排序,依次处理
跑步的人拿出来后再对应桶里面–
询问的人答案贡献就是 L[i?wi]+R[i+wi]L[i-w_i]+R[i+w_i]L[i?wi?]+R[i+wi?]
20opt:20\ opt:20 opt: 所有 si=1s_i=1si?=1
考虑 wiw_iwi? 会有答案当且仅当 wi=depiw_i=dep_iwi?=depi?
将跑步人的 tit_iti? 处++
然后对于 wi=depiw_i=dep_iwi?=depi? 答案为子树和
20opt:20\ opt:20 opt: 所有 ti=1t_i=1ti?=1
模仿 si=1s_i=1si?=1 的思路,假设第 iii 个人跑步时间为 li=depsil_i=dep_{s_i}li?=depsi?? 发现 wi+depi=ljw_i+dep_i=l_jwi?+depi?=lj?
时候会对答案产生贡献
发现这里 wi+depiw_i+dep_iwi?+depi? 为定值
联系链的情况,想到了用桶完成操作
访问一个点记录 b[wi+depi]b[w_i+dep_i]b[wi?+depi?]
更新时将人挂到对应 sis_isi? 上面 然后 b[li]++b[l_i]++b[li?]++
子树 DFS 完出来后 b[wi+depi]b[w_i+dep_i]b[wi?+depi?] 的增量就是答案
最后 20opt:20\ opt:20 opt: 正解
上一种情况给了我们很大的启发
将一个人走的路径拆为向上走和向下走, <si,lcai><s_i,lca_i><si?,lcai?> 和 <sonlcai,ti><sonlca_i,t_i><sonlcai?,ti?>
这里 sonlcaisonlca_isonlcai? 指包含 tit_iti? 的那个儿子
对于向上走发现对答案贡献只有当 wi+depi=depsiw_i+dep_i=dep_{s_i}wi?+depi?=depsi?? 成立
对于向下走发现对答案贡献只有当 wi=li?(depti?depi)w_i=l_i-(dep_{t_i}-dep_i)wi?=li??(depti???depi?) 成立,
变形可得 wi?depi=li?deptiw_i-dep_i=l_i-dep_{t_i}wi??depi?=li??depti??
可以模仿链建立两种不同的询问方式
然后是点差的常规操作
在 sis_isi? 挂对应 depsidep_{s_i}depsi?? 加 flcaflcaflca 挂对应 depsidep_{s_i}depsi?? 减
在 tit_iti? 挂对应 li?deptil_i-dep_{t_i}li??depti?? 加 lcalcalca 挂对应 li?deptil_i-dep_{t_i}li??depti?? 减
DFS遍历完子树后统计即可
代码
#include<set>
#include<map>
#include<cmath>
#include<deque>
#include<stack>
#include<ctime>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
#define LL long long
#define ULL unsigned long long
using namespace std;
int read(){
int f=1,x=0;char c=getchar();while(c<'0'||'9'<c){
if(c=='-')f=-1;c=getchar();}while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();return f*x;
}
#define MAXN 300000
#define INF 0x3f3f3f3f
struct Edge{
int v,nxt;
}edge[2*MAXN+5];
int ecnt,head[MAXN+5];
inline void Addedge(int u,int v){
edge[++ecnt]=(Edge){
v,head[u]},head[u]=ecnt;edge[++ecnt]=(Edge){
u,head[v]},head[v]=ecnt;return ;
}
int n,m,lg2,dep[MAXN+5],fa[MAXN+5][20];
int w[MAXN+5],s[MAXN+5],t[MAXN+5];
void dfs(int u){
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;if(v==fa[u][0]) continue;fa[v][0]=u,dep[v]=dep[u]+1,dfs(v);}return ;
}
void Prepare(){
for(int j=1;(1<<j)<=n;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];return ;
}
int Lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);int d=dep[u]-dep[v];for(int j=lg2;j>=0;j--)if(d&(1<<j))u=fa[u][j];if(u==v)return u;for(int j=lg2;j>=0;j--)if(fa[u][j]!=fa[v][j])u=fa[u][j],v=fa[v][j];return fa[u][0];
}
vector<int> Add1[MAXN+5],Sub1[MAXN+5],Add2[MAXN+5],Sub2[MAXN+5];
int c1[2*MAXN+5],c2[2*MAXN+5],ans[MAXN+5];
void Cal(int u,int fa){
int tmp1=c1[dep[u]+w[u]],tmp2=c2[w[u]-dep[u]+n];for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;if(v==fa) continue;Cal(v,u);}for(int i=0;i<int(Add1[u].size());i++) c1[Add1[u][i]]++;for(int i=0;i<int(Sub1[u].size());i++) c1[Sub1[u][i]]--;for(int i=0;i<int(Add2[u].size());i++) c2[Add2[u][i]+n]++;for(int i=0;i<int(Sub2[u].size());i++) c2[Sub2[u][i]+n]--;ans[u]=c1[dep[u]+w[u]]+c2[w[u]-dep[u]+n]-tmp1-tmp2;return ;
}
int main(){
n=read(),m=read(),lg2=(int)log2(n);for(int i=1;i<n;i++){
int u=read(),v=read();Addedge(u,v);}for(int i=1;i<=n;i++)w[i]=read();for(int i=1;i<=m;i++)s[i]=read(),t[i]=read();dfs(1);Prepare();for(int i=1;i<=m;i++){
int lca=Lca(s[i],t[i]);Add1[s[i]].push_back(dep[s[i]]);Sub1[fa[lca][0]].push_back(dep[s[i]]);int Len=dep[s[i]]+dep[t[i]]-2*dep[lca];Add2[t[i]].push_back(Len-dep[t[i]]);Sub2[lca].push_back(Len-dep[t[i]]);}Cal(1,0);for(int i=1;i<=n;i++)printf("%d",ans[i]),putchar(i==n?'\n':' ');return 0;
}