bzoj4381: [POI2015]Odwiedziny

来源:互联网 发布:极客大数据 编辑:程序博客网 时间:2024/06/08 03:15

点这里

这道题暴力跑最多n/m个点(m为步长),当m较小时飞慢。考虑DP[i][j]表示从i以j步长跳到根的和,询问可达到O(1+lca)。

这样对m>sqrt(n)的暴力,<sqrt(n)的DP,复杂度O(n*sqrt(n)+n*sqrt(n)+n*logn)可以。

另外up函数是利用树剖把x往上跳y下,同一个方向跳复杂度O(logn)。

UPD:MAIN上T了233。。。

UPD:UPD:lca一不小心写成了暴力:for (;top[x]!=top[y];x=fa[x])  这都能过也是醉了QAQ

#include<iostream>#include<cstdio>#include<cmath>#define N 50005using namespace std;int n,m,x,y,a[N],b[N],c[N],first[N],l;int fa[N],dep[N],size[N],Bson[N],top[N],ord[N],pos[N],cnt;int dp[N][255];struct Edg{int to,next;}e[N<<1];int read(){int x=0; char ch=getchar();while (ch<'0' || ch>'9') ch=getchar();while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }return x;}void link(int x,int y){e[++l]=(Edg){y,first[x]};first[x]=l;e[++l]=(Edg){x,first[y]};first[y]=l;}void dfs(int x){dep[x]=dep[fa[x]]+1;size[x]=1;for (int i=1,j=fa[x];i<=m;i++,j=fa[j])dp[x][i]=dp[j][i]+a[x];for (int i=first[x],j;i;i=e[i].next)if ((j=e[i].to)!=fa[x]){fa[j]=x;dfs(j);size[x]+=size[j];if (size[j]>size[Bson[x]]) Bson[x]=j;}}void dfs(int x,int y){top[x]=y;ord[x]=++cnt;pos[cnt]=x;if (Bson[x]) dfs(Bson[x],y);for (int i=first[x],j;i;i=e[i].next)if ((j=e[i].to)!=fa[x]&&j!=Bson[x])dfs(j,j);}int lca(int x,int y){for (;top[x]!=top[y];x=fa[top[x]])if (dep[top[x]]<dep[top[y]]) swap(x,y);return (dep[x]<dep[y])?x:y;}int up(int x,int y){if (dep[x]<=y) return 0;for (;(dep[x]-dep[top[x]])<y;x=fa[top[x]])y-=dep[x]-dep[top[x]]+1;return pos[ord[x]-y];}int jump(int x,int y,int s,int p){int ans=0;if (s<m){y=up(x,(dep[x]-dep[y]-p+s)/s*s);return dp[x][s]-dp[y][s];}for (;dep[x]>=dep[y]+p;x=up(x,s))ans+=a[x];return ans;}int main(){n=read();m=sqrt(n)/7*3+1;for (int i=1;i<=n;i++) a[i]=read();for (int i=1;i<n;i++) x=read(),y=read(),link(x,y);for (int i=1;i<=n;i++) b[i]=read();for (int i=1;i<n;i++) c[i]=read();dfs(1);dfs(1,1);for (int i=1;i<n;i++){int u=b[i],v=b[i+1],k=lca(u,v),len=dep[u]+dep[v]-2*dep[k];int ans=jump(u,k,c[i],0);if (len%c[i]) ans+=a[v],v=up(v,len%c[i]);ans+=jump(v,k,c[i],1);printf("%d\n",ans);}return 0;}


0 0
原创粉丝点击