BZOJ4381 : [POI2015]Odwiedziny

设$lim=\sqrt{n}$。

若$k<lim$,预处理出:

$F[i][x]$:$x$往上走$i$步到达的点。

$S[i][x]$:$x$不断往上走$i$步经过的点的和。

直接$O(1)$查询即可。

若$k\geq lim$:

查询时用树链剖分划分为$O(\log n)$条重链,在每条重链上暴力往上跳。

时间复杂度$O(\log n+\sqrt{n})$。

总时间复杂度$O(n\sqrt{n})$。

#include<cstdio>
const int N=50010,M=224;
int n,lim,i,j,x,y,a[N],b[N],g[N],v[N<<1],nxt[N<<1],ed;
int d[N],f[N],size[N],son[N],top[N],loc[N],seq[N],dfn;
int F[M][N],S[M][N];
inline void swap(int&a,int&b){int c=a;a=b;b=c;}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
  S[1][x]=S[1][F[1][x]=f[x]]+a[x];
  for(int i=2;i<lim;i++)S[i][x]=S[i][F[i][x]=f[F[i-1][x]]]+a[x];
  d[x]=d[f[x]]+1,size[x]=1;
  for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
    f[v[i]]=x,dfs(v[i]),size[x]+=size[v[i]];
    if(size[v[i]]>size[son[x]])son[x]=v[i];
  }
}
void dfs2(int x,int y){
  top[x]=y,seq[loc[x]=++dfn]=x;
  if(son[x])dfs2(son[x],y);
  for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]&&v[i]!=son[x])dfs2(v[i],v[i]);
}
inline int lca(int x,int y){
  while(top[x]!=top[y]){
    if(d[top[x]]<d[top[y]])swap(x,y);
    x=f[top[x]];
  }
  return d[x]<d[y]?x:y;
}
inline int father(int x,int y){
  while(loc[x]-loc[top[x]]<y){
    y-=loc[x]-loc[top[x]]+1;
    x=f[top[x]];
  }
  return seq[loc[x]-y];
}
inline int up(int x,int y,int k){
  y=father(x,d[x]-d[y]-(d[x]-d[y])%k);
  if(k<lim)return S[k][x]-S[k][y]+a[y];
  int t=0,i;
  while(top[x]!=top[y]){
    for(i=loc[x];i>=loc[top[x]];i-=k)t+=a[seq[i]];
    x=father(x,loc[x]-i);
  }
  for(i=loc[x];i>=loc[y];i-=k)t+=a[seq[i]];
  return t;
}
inline int query(int x,int y,int k){
  int z=lca(x,y),t=up(x,z,k);
  if((d[x]+d[y]-d[z]*2)%k)t=a[y];
  if(z==y)return t;
  if((d[x]-d[z])%k==0)t-=a[z];
  int tmp=((d[z]-d[x])%k+k)%k;
  if(d[y]-d[z]-tmp<0)return t;
  return t+up(father(y,(d[y]-d[z]-tmp)%k),z,k);
}
int main(){
  scanf("%d",&n);
  while(lim*lim<n)lim++;
  for(i=1;i<=n;i++)scanf("%d",&a[i]);
  for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
  dfs(1),dfs2(1,1);
  for(i=1;i<=n;i++)scanf("%d",&b[i]);
  for(i=1;i<n;i++)scanf("%d",&x),printf("%d\n",query(b[i],b[i+1],x));
  return 0;
}

  

时间: 2024-11-03 21:08:26

BZOJ4381 : [POI2015]Odwiedziny的相关文章

[POI2015]Odwiedziny

[POI2015]Odwiedziny 题目大意: 一棵\(n(n\le5\times10^4)\)个点的树,\(n\)次询问从一个点到另一个点的路径上,每次跳\(k\)个点,所经过的点权和. 思路: 分块思想. 当\(k\ge\sqrt n\)时,显然每次询问不会跳超过\(\sqrt n\)次,可以借助树链剖分在\(\mathcal O(\sqrt n)\)的时间内暴力完成询问. 当\(k<\sqrt n\)时,预处理从一个点出发,每次跳\(k\)格,跳到根结点的权值和.可以\(\mathca

@bzoj - [email&#160;protected] [POI2015] Odwiedziny

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一棵 n 个点的树,树上每条边的长度都为 1 ,第 i 个点的权值为 a[i]. Byteasar 会按照某个 1 到 n 的全排列 b 走 n-1 次,第 i 次他会从 b[i] 点走到 b[i+1] 点,并且这一次的步伐大小为 c[i]. 对于一次行走,假设起点为 x,终点为

[Poi2015]

[POI2015]?asuchy 一看以为是sb题 简单来说就是每个人获得热量要尽量多 不能找别人 首先这道题好像我自己找不到NIE的情况 很容易想到一个优化 如果一个数/2>另一个数 那么一定选这个数 然后我想着其他的话就随便分配一个 然后会得出下一个 其实这样做是错的 因为你选完之后不知道下一个会不会是来降低我当前选的那一个的热量使得我当前的原来最优变成不是最优 然后这样子 怎么办呢??? 废话 膜题解 膜拜Claris 我们既然不知道下一个会不会来降低热量 不妨把每个食物的状态都定下来 让

bzoj 4385: [POI2015]Wilcze do?y

4385: [POI2015]Wilcze do?y Description 给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0.请找到最长的一段连续区间,使得该区间内所有数字之和不超过p. Input 第一行包含三个整数n,p,d(1<=d<=n<=2000000,0<=p<=10^16).第二行包含n个正整数,依次表示序列中每个数w[i](1<=w[i]<=10^9). Output 包含一行一个正整数,即修改后能

BZOJ 3747: [POI2015]Kinoman( 线段树 )

线段树... 我们可以枚举左端点 , 然后用线段树找出所有右端点中的最大值 . ----------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( i

poi2015 bzoj4377-4386训练

就按时间顺序写吧 完成度:8/10 3.30 bzoj4385 首先一定是删去连续d个数,然后枚举终点,起点显然有单调性,用单调队列乱搞搞就可以啦 bzoj4378 首先才结论:可行当且仅当把所有大于s的数全变成s然后看所有的数的和大于等于c*s,然后两个树状数组分别维护<=s的和及个数即可,注意需要离散化 3.31 bzoj4377 设一段的起点处的数为x,则m个限制条件就可以转化为x在若干个区间(或两个区间的并)里面,然后把这些区间交起来就得到了x的范围,算出个数然后减去最后m-1个数(没有

【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)

3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 830  Solved: 338 Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,-,r天内所有的电影.如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值

【BZOJ4378】[POI2015]Logistyka 树状数组

[BZOJ4378][POI2015]Logistyka Description 维护一个长度为n的序列,一开始都是0,支持以下两种操作:1.U k a 将序列中第k个数修改为a.2.Z c s 在这个序列上,每次选出c个正数,并将它们都减去1,询问能否进行s次操作.每次询问独立,即每次询问不会对序列进行修改. Input 第一行包含两个正整数n,m(1<=n,m<=1000000),分别表示序列长度和操作次数.接下来m行为m个操作,其中1<=k,c<=n,0<=a<=

BZOJ 4384: [POI2015]Trzy wie?e

4384: [POI2015]Trzy wie?e Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 217  Solved: 61[Submit][Status][Discuss] Description 给定一个长度为n的仅包含'B'.'C'.'S'三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符,要么有多种字符,但是没有任意两种字符出现次数相同. Input 第一行包含一个正整数n(1<=n<=1000000),表示字符