1. 程式人生 > >洛谷P1600 天天愛跑步(NOIp2016)(BZOJ4719)

洛谷P1600 天天愛跑步(NOIp2016)(BZOJ4719)

LCA

炒雞難的一題。。。碼量還不小。。。

只想到拆成鏈,然而不知道怎麼實現。。。只好認慫去看題解。。。

考慮每條路徑,拆成兩個鏈。一個從s到LCA,另一個從LCA到t。如果LCA有貢獻的話就把答案-1(不然就算重啦)。

然後在每個s打個1,在LCA上打個-1,那麼就變成求一個節點的子樹和。

對於點i,當depth[s]depth[i]=w[i]時產生貢獻。那麼令num[i]=w[i]+depth[i]。查詢時更新num[i]即可。
對於另一條鏈類似,當depth[t]depth[i]=disw[i]時產生貢獻。同樣令num[i]=w[i]depth[i],不過這時d

isdepth[t]可能為負。因此需要把陣列平移。

LCA的話我用的是Tarjan,時間複雜度O(n+m)

當然倍增也是可以的。

程式碼:

#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; }