BZOJ4381: [POI2015]Odwiedziny
Description
给定一棵n个点的树,树上每条边的长度都为1,第i个点的权值为a[i]。
Byteasar想要走遍这整棵树,他会按照某个1到n的全排列b走n-1次,第i次他会从b[i]点走到b[i+1]点,并且这一次的步伐大小为c[i]。
对于一次行走,假设起点为x,终点为y,步伐为k,那么Byteasar会从x开始,每步往前走k步,如果最后不足k步就能到达y,那么他会一步走到y。
请帮助Byteasar统计出每一次行走时经过的所有点的权值和。
Input
第一行包含一个正整数n(2<=n<=50000)。表示节点的个数。
第二行包含n个正整数,其中第i个数为a[i](1<=a[i]<=10000),分别表示每个点的权值。
接下来n-1行,每行包含两个正整数u,v(1<=u,v<=n),表示u与v之间有一条边。
接下来一行包含n个互不相同的正整数,其中第i个数为b[i](1<=b[i]<=n),表示行走路线。
接下来一行包含n-1个正整数,其中第i个数为c[i](1<=c[i]<n),表示每次行走的步伐大小。
Output
包含n-1行,每行一个正整数,依次输出每次行走时经过的所有点的权值和
Sample Input
5
1 2 3 4 5
1 2
2 3
3 4
3 5
4 1 5 2 3
1 3 1 1
1 2 3 4 5
1 2
2 3
3 4
3 5
4 1 5 2 3
1 3 1 1
Sample Output
10
6
10
5
6
10
5
对于k比较大的情况,直接暴力。
对于k比较小的情况,我们一起计算。
具体实现看code
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=50010; int n,val[maxn],b[maxn],c[maxn],first[maxn],next[maxn<<1],to[maxn<<1],e; void AddEdge(int u,int v) { to[++e]=v;next[e]=first[u];first[u]=e; to[++e]=u;next[e]=first[v];first[v]=e; } int dep[maxn],anc[maxn][20]; void dfs(int x,int fa) { dep[x]=dep[fa]+1;anc[x][0]=fa; rep(i,1,19) anc[x][i]=anc[anc[x][i-1]][i-1]; ren if(to[i]!=fa) dfs(to[i],x); } int go(int x,int k) { rep(i,0,19) if(k>>i&1) x=anc[x][i]; return x; } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); dwn(i,19,0) if(1<<i<=dep[x]-dep[y]) x=anc[x][i]; dwn(i,19,0) if(anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i]; return x==y?x:anc[x][0]; } int vis[maxn],clo; void add(int& ans,int x) { if(vis[x]!=clo) ans+=val[x]; vis[x]=clo; } int solve(int x,int y,int k) { int z=lca(x,y),len=dep[x]+dep[y]-dep[z]*2,ans=0;clo++; while(1) { add(ans,x);int t=go(x,k); if(dep[t]>=dep[z]) x=t; else break; } add(ans,y);y=go(y,len%k); while(dep[y]>dep[z]) { add(ans,y);int t=go(y,k); if(dep[t]>dep[z]) y=t; else break; } return ans; } int ans[maxn],first2[maxn],id[maxn],next2[maxn],cnt; void AddQuery(int c,int i) { id[++cnt]=i;next2[cnt]=first2[c];first2[c]=cnt; } int dis[maxn]; void dfs2(int x,int fa,int gap) { dis[x]=val[x];if(dep[x]>gap) dis[x]+=dis[go(x,gap)]; ren if(to[i]!=fa) dfs2(to[i],x,gap); } int main() { n=read();rep(i,1,n) val[i]=read(); rep(i,2,n) AddEdge(read(),read()); dfs(1,0);int SIZE=10; rep(i,1,n) b[i]=read(); rep(i,2,n) { c[i]=read(); if(c[i]>SIZE) ans[i]=solve(b[i-1],b[i],c[i]); else AddQuery(c[i],i); } rep(i,1,SIZE) if(first2[i]) { dfs2(1,0,i); for(int j=first2[i];j;j=next2[j]) { int u=b[id[j]-1],v=b[id[j]],z=lca(u,v); int len=dep[u]+dep[v]-2*dep[z],x=go(u,(dep[u]-dep[z])/i*i); ans[id[j]]+=dis[u]-dis[x]+val[x]; int y=go(v,len%i),w=go(y,(dep[y]-dep[z])/i*i); if(y!=v) ans[id[j]]+=val[v]; ans[id[j]]+=dis[y]-dis[w]+val[w]; if(x==w) ans[id[j]]-=val[w]; } } rep(i,2,n) printf("%d\n",ans[i]); return ~~(0-0); }