P1600 [NOIP2016 提高组] 天天爱跑步
这题被我 3 min 胡出来了的样子。
考虑,m 对点 $(s_i,t_i)$ 去贡献点 j。
考虑贡献式: $dep_s+dep_x-2dep_{lca(s,x)}=w_x$。
如果 $x\in [s,lca(s,t)]$,那么 $dep_s-dep_x=w_x,dep_s=dep_x+w_x$,用 $dep_s_$ 去贡献即可。具体我不太会,用了个比较蠢的分块维护桶。
$ x\in[lca(s,t),t]$,那么 $dep_s+dep_x-2*dep_{lca(s,x)}=w_x$,此时 $lca(s,x)=lca(s,t)$,$dep_s-2*dep{lca(s,t)}=w_x-dep_x$,考虑用这东西去贡献下就好。由于 $w_x-dep_x \in[-n,n]$,要值域平移。
注意下空间。时复 $O(n\sqrt{n}\log n)$。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#define ll long long
using namespace std;
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
ll lrd() {
ll f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
/* dis=w_x dep_A+dep_x-2*dep_lca=w_x dep_A-2*dep_lca=w_x-dep_x
分块,块内维护个桶
*/
const int N=(int)(3e5+2),M=410;
struct edge {
int nex,to;
}e[N<<1];
int dep[N],fa[N],top[N],son[N],sz[N],id[N],rk[N],tot;
int head[N],cnt,w[N],ans[N],n,m;
void add_edge(int x,int y) {
e[++cnt].nex=head[x]; e[cnt].to=y; head[x]=cnt;
}
void dfs1(int x,int ff) {
dep[x]=dep[ff]+1; fa[x]=ff; sz[x]=1;
for(int i=head[x];i;i=e[i].nex) {
int y=e[i].to; if(y==ff) continue;
dfs1(y,x); sz[x]+=sz[y];
if(sz[y]>sz[son[x]]) son[x]=y;
}
}
void dfs2(int x,int tp) {
top[x]=tp; id[x]=++tot; rk[tot]=x;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i;i=e[i].nex) {
int y=e[i].to; if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
#define K (int)(3e5)
int L[M],R[M],bid[N],bl,cnt1[M][N<<1],cnt2[M][N<<1];
void init() {
bl=sqrt(1.0*n*1.8);
for(int i=1;i<=n;i++) bid[i]=(i-1)/bl+1;
for(int i=1;i<=bid[n];i++) L[i]=(i-1)*bl+1,R[i]=i*bl; R[bid[n]]=n;
}
void upt1(int l,int r,int pos) {
if(bid[l]==bid[r]) {
for(int i=l;i<=r;i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i];
} else {
for(int i=l;i<=R[bid[l]];i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i];
for(int i=L[bid[r]];i<=r;i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i];
for(int i=bid[l]+1;i<bid[r];i++) ++cnt1[i][pos+K];
}
}
void upt2(int l,int r,int pos) {
if(bid[l]==bid[r]) {
for(int i=l;i<=r;i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i];
} else {
for(int i=l;i<=R[bid[l]];i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i];
for(int i=L[bid[r]];i<=r;i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i];
for(int i=bid[l]+1;i<bid[r];i++) ++cnt2[i][pos+K];
}
}
int query(int x) {
//cout<<w[x]-dep[x]<<endl;
return ans[x]+cnt1[bid[x]][w[rk[x]]+dep[rk[x]]+K]+cnt2[bid[x]][w[rk[x]]-dep[rk[x]]+K];
}
int LCA(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
// dep_A-dep_x+dis=w_x w_x+dep_x=dep_A+dis
// dep_A-dep_x=w_x w_x+dep_x=dep_A
// all_dis-(dep_A-dep_x)=all_dis-dep_A+dep_x=w_x
// w_x-dep_x=all_dis-dep_A
/*
dep_x+dep_y-2*dep_lca=w_y
dep_A-dep_x=w_x
1. dep_x=w_y+dep_y
2. dep_x-2*dep_d=w_y-dep_y
*/
void update1(int x,int y) {
int A=x;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
upt1(id[top[x]],id[x],dep[A]);
x=fa[top[x]];
}
if(id[x]>id[y]) swap(x,y);
upt1(id[x],id[y],dep[A]);
}
void update2(int depd,int u,int x,int y) {
int A=u;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
upt2(id[top[x]],id[x],dep[A]-2*depd);
x=fa[top[x]];
}
if(id[x]>id[y]) swap(x,y);
upt2(id[x],id[y],dep[A]-2*depd);
}
void pr(int x) {
if(x<0) {putchar('-');x=-x;}
if(x>9) pr(x/10);
putchar(x%10+'0');
}
int main() {
int x,y;
n=rd(); m=rd();
for(int i=1;i<n;i++) {
x=rd(); y=rd();
add_edge(x,y); add_edge(y,x);
}
for(int i=1;i<=n;i++) w[i]=rd();
dfs1(1,0); dfs2(1,0);
init();
while(m--) {
x=rd(); y=rd(); int d=LCA(x,y);
update1(x,d); update2(dep[d],x,y,d);
if(dep[x]-dep[d]==w[d]) --ans[id[d]];
// cout<<dep[x]+dep[y]-2*dep[d]<<":\n";
// puts("");
}
for(int i=1;i<=n;i++) pr(query(id[i])),putchar(' ');
return 0;
}

浙公网安备 33010602011771号