题目描述 传送门
我觉得好难好难啊,看题解我都看不懂(我觉得实现起来有点麻烦)。
总结一下:
首先也许可以想出S=1和T=1的数据的做法,然后想到把S->T路径拆成S->LCA和LCA->T.
然后要想到一个点i可观测到的人一定满足:
S->LCA路径:
depth[i]+w[i]=depth[S]
LCA->T路径:
distance(S,i)=w[i]
即depth[S]+depth[i]−2∗depth[LCA]=w[i]
整理得: depth[i]−w[i]=depth[T]−distance(S,T)
等式右边的都是定值,可以预处理好。
然后两遍DFS分别处理S->LCA和LCA->T的情况,并用桶记录有多少个满足条件的等式右边。
注意到对于一个点如果一条路径没有经过它即使满足等式也不行。
然而这样还会重复算到每条路径的LCA的答案(因为LCA既在S->LCA又在LCA->T)所以最后减去重复的才是答案。
//代码参考dalao的
#include
#include
#include
#include
#include
using namespace std;
const int maxn=3e5+5,maxm=3e5+5,N=3e5;
int maxd=0;
struct Edge{
int to,nxt;
Edge(int a=0,int b=0):to(a),nxt(b){}
}edge[maxm*2];
int n,m;
int s[maxn],t[maxn],lca[maxn],len[maxn];
int cnt=0,h[maxn];
int f[maxn],depth[maxn],son[maxn],size[maxn],top[maxn];
int w[maxn],tong[maxn*2],tong2[maxn*2],num[maxn],ans[maxn];
vector<int> v[maxn],v2[maxn],v3[maxn];
void addedge(int from,int to){
edge[++cnt]=Edge(to,h[from]);
h[from]=cnt;
}
void dfs1(int u,int fa){
f[u]=fa;
depth[u]=depth[fa]+1;
son[u]=0;
size[u]=1;
for(int i=h[u];i;i=edge[i].nxt) if(edge[i].to!=fa) {
int v=edge[i].to;
dfs1(v,u);
if(size[v]>size[son[u]]) son[u]=v;
size[u]+=size[v];
}
}
void dfs2(int u,int tp){
top[u]=tp;
if(size[u]>1) dfs2(son[u],tp);
for(int i=h[u];i;i=edge[i].nxt) if(edge[i].to!=f[u]&&edge[i].to!=son[u])
dfs2(edge[i].to,edge[i].to);
}
int get_lca(int x,int y){ //我用树链剖分求的LCA
int f1=top[x],f2=top[y];
while(f1!=f2){
if(depth[f1]if(depth[x]return y;
}
void dfss(int u,int fa){
int now=depth[u]+w[u],x;
if(nowfor(int i=h[u];i;i=edge[i].nxt)if(edge[i].to!=fa){
dfss(edge[i].to,u);
}
tong[depth[u]]+=num[u];
if(nowfor(int i=0;ivoid dfst(int u,int fa){
int now=depth[u]-w[u]+N;
int x=tong2[now];
for(int i=h[u];i;i=edge[i].nxt)if(edge[i].to!=fa){
dfst(edge[i].to,u);
}
for(int i=0;ifor(int i=0;iint main(){
memset(h,0,sizeof(h));
memset(num,0,sizeof(num));
cin>>n>>m;
for(int i=0;i1;i++){
int a,b;
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
depth[1]=1;
son[0]=0;
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=n;i++) maxd=max(maxd,depth[i]);
maxd++;
for(int i=1;i<=m;i++){
scanf("%d%d",&s[i],&t[i]);
lca[i]=get_lca(s[i],t[i]);
len[i]=depth[s[i]]+depth[t[i]]-depth[lca[i]]*2;
v[lca[i]].push_back(depth[s[i]]);
num[s[i]]++;
}
dfss(1,1);
for(int i=1;i<=m;i++){
v2[t[i]].push_back(depth[t[i]]-len[i]);
v3[lca[i]].push_back(depth[t[i]]-len[i]);
}
dfst(1,1);
for(int i=1;i<=m;i++) if(depth[s[i]]-depth[lca[i]]==w[lca[i]]) ans[lca[i]]--;
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}
一开始求LCA还写错了QWQ
NOIp提高组2016 AK