洛谷P1600 天天愛跑步(NOIp2016)(BZOJ4719)
阿新 • • 發佈:2018-12-31
LCA
炒雞難的一題。。。碼量還不小。。。
只想到拆成鏈,然而不知道怎麼實現。。。只好認慫去看題解。。。
考慮每條路徑,拆成兩個鏈。一個從s到LCA,另一個從LCA到t。如果LCA有貢獻的話就把答案-1(不然就算重啦)。
然後在每個s打個1,在LCA上打個-1,那麼就變成求一個節點的子樹和。
對於點
對於另一條鏈類似,當 is−depth[t]
LCA的話我用的是Tarjan,時間複雜度
當然倍增也是可以的。
程式碼:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define MAXN 300000
#define MAXM 600000
using namespace std;
struct edge{ int next,to; };
struct route{ int s,t,lca,dis; };
int n,m,k,md;
int w[MAXN+5],h1[MAXN+5],h2[MAXN+5],fa[MAXN+5],depth[MAXN+5],num[MAXN+5],ans[MAXN+5],t[MAXN+5],tt[MAXM+5];
edge ed[MAXM*2+5];
route p[MAXN+5];
vector <int> t1[MAXN+5],t2[MAXN+5],t3[MAXN+5];
bool f[MAXN+5];
inline char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1 ,100000,stdin);
if (l==r) return EOF; return *l++;
}
inline int _read(){
int num=0; char ch=readc();
while (ch<'0'||ch>'9') ch=readc();
while (ch>='0'&&ch<='9') { num=num*10+ch-48; ch=readc(); } return num;
}
void addedge(int x,int y,int *h){
ed[++k].next=h[x]; ed[k].to=y; h[x]=k;
}
int findfather(int x){
if (fa[x]==x) return x;
return fa[x]=findfather(fa[x]);
}
void Tarjan(int x,int father){
fa[x]=x; f[x]=true;
for (int i=h2[x];i;i=ed[i].next){
int v=ed[i].to;
if (x==p[v].s&&f[p[v].t]) p[v].lca=findfather(p[v].t);
if (x==p[v].t&&f[p[v].s]) p[v].lca=findfather(p[v].s);
}
for (int i=h1[x];i;i=ed[i].next)
if (ed[i].to!=father){
int v=ed[i].to; depth[v]=depth[x]+1; Tarjan(v,x); fa[v]=x;
}
}
void dfs1(int x,int father){
int now=w[x]+depth[x],l; if (now<=md) l=t[now];
for (int i=h1[x];i;i=ed[i].next)
if (ed[i].to!=father) dfs1(ed[i].to,x);
t[depth[x]]+=num[x]; if (now<=md) ans[x]=t[now]-l;
int len=t1[x].size();
for (int i=0;i<len;i++) t[depth[t1[x][i]]]--;
}
void dfs2(int x,int father){
int now=depth[x]-w[x]+MAXN,l; l=tt[now];
for (int i=h1[x];i;i=ed[i].next)
if (ed[i].to!=father) dfs2(ed[i].to,x);
int len=t2[x].size(); for (int i=0;i<len;i++) tt[MAXN+t2[x][i]]++;
len=t3[x].size(); ans[x]+=tt[now]-l;
for (int i=0;i<len;i++) tt[MAXN+t3[x][i]]--;
}
int main(){
n=_read(); m=_read();
for (int i=1;i<n;i++){
int u=_read(),v=_read(); addedge(u,v,h1); addedge(v,u,h1);
}
for (int i=1;i<=n;i++) w[i]=_read();
for (int i=1;i<=m;i++){
p[i].s=_read(); p[i].t=_read(); num[p[i].s]++; addedge(p[i].s,i,h2); addedge(p[i].t,i,h2);
}
Tarjan(1,0);
for (int i=1;i<=n;i++) md=max(md,depth[i]);
for (int i=1;i<=m;i++){
p[i].dis=depth[p[i].s]+depth[p[i].t]-depth[p[i].lca]*2;
t1[p[i].lca].push_back(p[i].s);
}
dfs1(1,0);
for (int i=1;i<=m;i++){
t2[p[i].t].push_back(depth[p[i].t]-p[i].dis);
t3[p[i].lca].push_back(depth[p[i].t]-p[i].dis);
}
dfs2(1,0);
for (int i=1;i<=m;i++) if (depth[p[i].s]-w[p[i].lca]==depth[p[i].lca]) ans[p[i].lca]--;
for (int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}