标签:标记 方式 art head stream [1] 节点 代码 结束
http://uoj.ac/problem/261 (题目链接)
给出一棵树,给出一些起点和终点,没走一条路径耗费时间1,每个节点上有一个权值w,问有多少条路径经过这个节点时所用的时间恰好是w。
转自:http://blog.csdn.net/haarmony/article/details/53259338
约定第${i}$个人起终点的${lca(s[i],t[i])}$为${lca[i]}$,点${i}$深度为${deep[i]}$
我们发现如果做个变换,即${deep[u]+w[u]==deep[s[i]]}$
与${w[u]-deep[u]==deep[s[i]]-2*deep[lca[i]]}$的话,式子右边是不变的,那是不是可以开一个${cnt}$数组来统计一下子树中等于右式的出发点和结束点的个数呢?
细节很多,想清楚再写。
// uoj261
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define inf 2147483640
#define LL long long
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;
const int T=300000,maxn=300010;
struct edge {int to,next;}e[maxn<<1],g[maxn],ct[maxn];
int cnt[2][10000010],h[maxn],hh[maxn],head[maxn];
int deep[maxn],fa[maxn][30],bin[30],Lca[maxn];
int n,m,c1,c2,c3,ans[maxn],cs[maxn],w[maxn],s[maxn],t[maxn];
void linke(int u,int v) {
e[++c1].to=v;e[c1].next=head[u];head[u]=c1;
e[++c1].to=u;e[c1].next=head[v];head[v]=c1;
}
void linkg(int u,int v) {g[++c2].to=v;g[c2].next=h[u];h[u]=c2;}
void linkt(int u,int v) {ct[++c3].to=v;ct[c3].next=hh[u];hh[u]=c3;}
void dfs(int x) {
for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
fa[e[i].to][0]=x;
deep[e[i].to]=deep[x]+1;
dfs(e[i].to);
}
}
int lca(int x,int y) {
if (deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
for (int i=0;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return x==y ? x : fa[x][0];
}
void dfs(int x,int ta,int tb) {
for (int j,i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
j=e[i].to;
dfs(j,cnt[0][w[j]+deep[j]+T],cnt[1][w[j]-deep[j]+T]);
}
cnt[0][deep[x]+T]+=cs[x];
for (int j,i=hh[x];i;i=ct[i].next) {
j=ct[i].to;
cnt[1][deep[s[j]]-deep[Lca[j]]*2+T]++;
}
ans[x]+=cnt[0][w[x]+deep[x]+T]+cnt[1][w[x]-deep[x]+T]-ta-tb;
for (int j,i=h[x];i;i=g[i].next) {
j=g[i].to;
if (w[x]+deep[x]==deep[s[j]]) ans[x]--;
cnt[0][deep[s[j]]+T]--;cnt[1][deep[s[i]]-2*deep[x]+T]--;
}
}
int main() {
bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
scanf("%d%d",&n,&m);
for (int u,v,i=1;i<n;i++) {
scanf("%d%d",&u,&v);
linke(u,v);
}
dfs(1);
for (int i=1;i<=n;i++) scanf("%d",&w[i]);
for (int i=1;i<=m;i++) {
scanf("%d%d",&s[i],&t[i]);
Lca[i]=lca(s[i],t[i]);cs[s[i]]++;
linkg(Lca[i],i);
linkt(t[i],i);
}
dfs(1,0,0);
for (int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}
标签:标记 方式 art head stream [1] 节点 代码 结束
原文地址:http://www.cnblogs.com/MashiroSky/p/6159122.html