题意

给出一棵N 个节点的树,树上的每个节点都有一个权值$a_i$。

有Q 次询问,每次在树上选中两个点u, v,考虑所有在简单路径u, v 上(包括u, v)的点构成的集合S。

求$\sum_{w∈S}{a_w or dist(u,w)}$

其中dist(u,w) 为简单路径u,w 上的边数,or 是按位或。


思考

设f[i][j]表示从第i个节点开始,总共跳了$2^j$个节点得到的答案,g[i][j]表示从第i个节点开始,向下跳了$2^j$个节点得到的答案。这些状态的转移只要考虑后半部分最高位上1的贡献。

接下来对于查询u,v,我们算出其lca。对于u-lca,可以用倍增求出答案。由于倍增时每次的长度都至少会是以前的一半,那么某些二进制位上在以后一定都会是1,而且之前求出的f和它是独立的。对于lca-v的答案,可以先向上跳一些深度,再用g类似地求出答案。


代码

 // luogu-judger-enable-o2
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn=6E5+;
const int layer=;
int n,T;
int size,head[maxn*];
int root,dep[maxn];
ll val[maxn],fa[maxn][layer],cnt[maxn][layer],up[maxn][layer],down[maxn][layer];
inline int read()
{
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
int sum=ch-'';
ch=getchar();
while(isdigit(ch))
{
sum=sum*+ch-'';
ch=getchar();
}
return sum;
}
void write(ll x)
{
if(x>=)
write(x/);
putchar(''+x%);
}
inline void writen(ll x)
{
write(x);
putchar('\n');
}
struct edge
{
int to,next;
}E[maxn*];
inline void add(int u,int v)
{
E[++size].to=v;
E[size].next=head[u];
head[u]=size;
}
void dfs(int u,int F,int d)
{
fa[u][]=F;
dep[u]=d;
for(int i=;i<layer;++i)
fa[u][i]=fa[fa[u][i-]][i-];
for(int i=;i<layer;++i)
cnt[u][i]=cnt[F][i]+((val[u]&(<<i))>);
up[u][]=down[u][]=val[u];
for(int i=;i<layer;++i)
{
up[u][i]=up[u][i-]+up[fa[u][i-]][i-]+(ll)(<<(i-))*((<<(i-))-cnt[fa[u][i-]][i-]+cnt[fa[u][i]][i-]);
down[u][i]=down[u][i-]+down[fa[u][i-]][i-]+(ll)(<<(i-))*((<<(i-))-cnt[u][i-]+cnt[fa[u][i-]][i-]);
}
for(int i=head[u];i;i=E[i].next)
{
int v=E[i].to;
if(v==F)
continue;
dfs(v,u,d+);
}
}
inline int jump(int x,int d)
{
for(int i=;i<layer;++i)
if(d&(<<i))
x=fa[x][i];
return x;
}
inline int lca(int x,int y)
{
if(dep[x]<dep[y])
swap(x,y);
int d=dep[x]-dep[y];
x=jump(x,d);
if(x==y)
return x;
for(int i=layer-;i>=;--i)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][];
}
inline ll get1(int x,int to)
{
if(x==to)
return ;
ll sum=;
for(int i=layer-;i>=;--i)
if(dep[fa[x][i]]>=dep[to])
{
sum+=up[x][i];
x=fa[x][i];
sum+=(dep[x]-dep[to]-(cnt[x][i]-cnt[to][i]))*(ll)(<<i);
}
return sum;
}
int wait[],c[],tot;
inline ll get2(int x,int to)
{
if(x==to)
return val[x];
if(dep[x]>dep[to])
return ;
ll sum=;
tot=;
int from=to;
int d=dep[to]-dep[x]+;
for(int i=;i<layer;++i)
if(d&(<<i))
{
wait[++tot]=to;
c[tot]=i;
to=fa[to][i];
}
for(int i=tot;i>=;--i)
{
int u=wait[i];
sum+=down[u][c[i]];
if(c[i])
sum+=(ll)(<<(c[i]))*(dep[from]-dep[u]-(cnt[from][c[i]]-cnt[u][c[i]]));
}
return sum;
}
int main()
{
// freopen("C1.in","r",stdin);
// freopen("C.out","w",stdout);
ios::sync_with_stdio(false);
n=read(),T=read();
for(int i=;i<=n;++i)
val[i]=read();
for(int i=;i<=n;++i)
{
int x=read(),y=read();
add(x,y);
add(y,x);
}
root=n*;
add(n+,);
for(int i=n+;i<=root;++i)
add(i,i-);
dfs(root,root,);
while(T--)
{
int x,y,z,d;
x=read(),y=read();
z=lca(x,y);
d=dep[x]-dep[z];
int q=jump(z,d);
// cout<<x<<" "<<z<<" "<<q<<endl;
writen(get1(x,z)+get2(q,y)-get2(q,fa[z][]));
}
return ;
}

[校内训练19_09_02]C的更多相关文章

  1. [校内训练19_09_02]A

    题意 给出N 个形如$f_i(x) = a_i x^2 + b_i x $的二次函数. 有Q 次询问,每次给出一个x,询问$max{\{f_i(x)\}}$.$N,Q \leq 5*10^5$. 思考 ...

  2. [4.14校内训练赛by hzwer]

    来自FallDream的博客,未经允许,请勿转载,谢谢. hzwer又出丧题虐人 4道noi....        很奇怪 每次黄学长出题总有一题我做过了. 嗯题目你们自己看看呗 好难解释 ----- ...

  3. [2017.4.7校内训练赛by hzwer]

    来自FallDream的博客,未经允许,请勿转载,谢谢. 报警啦.......hzwer又出丧题虐人啦..... 4道ctsc...有一道前几天做过了,一道傻逼哈希还wa了十几次,勉强过了3题..我好 ...

  4. [3.24校内训练赛by hzwer]

    来自FallDream的博客,未经允许,请勿转载,谢谢. ----------------------------------------------------------------------- ...

  5. 19_04_19校内训练[Game]

    题意 给出n,等概率地生成一个1~n的数列.现在有n个人从左到右站成一排,每个人拿有当前数列位置上的数字,并且一开始都不知道数字是多少(但知道n是多少).从左到右让每个人进行如下选择: 1.选择保留自 ...

  6. 19_04_02校内训练[deadline]

    题意 给出一个二分图,左边为A集合,右边为B集合,要求把A集合中每一个点染为黑白两色中的一种,B集合中的颜色已定.染色后对于原本相邻且颜色相同的点,建立新的二分图,即得到了两个新的二分图,它们是独立的 ...

  7. 平面图转对偶图&19_03_21校内训练 [Everfeel]

    对于每个平面图,都有唯一一个对偶图与之对应.若G‘是平面图G的对偶图,则满足: G'中每一条边的两个节点对应着G中有公共边的面,包括最外部无限大的面. 直观地讲,红色标出来的图就是蓝色标出的图的对偶图 ...

  8. fzyzojP3979 -- [校内训练20180914]魔法方阵

    原题见CF632F https://blog.csdn.net/Steaunk/article/details/80217764 这个比较神仙了 点边转化, 把max硬生生转化成了路径最大值,再考虑所 ...

  9. fzyzojP3580 -- [校内训练-互测20180315]小基的高智商测试

    题目还有一个条件是,x>y的y只会出现一次(每个数直接大于它的只有一个) n<=5000 是[HNOI2015]实验比较 的加强版 g(i,j,k)其实可以递推:g(i,j,k)=g(i- ...

随机推荐

  1. springBoot从入门到源码分析

    先分享一个springBoot搭建学习项目,和springboot多数据源项目的传送门:https://github.com/1057234721/springBoot 1. SpringBoot快速 ...

  2. Hadoop Authentication

    我被被派去做别的事情了,所以与hadoop相关的工作就只能搁下.写篇总结,把最近遇到的和kerberos相关的东西列一下. JAAS是Java 认证和授权服务(Java Authentication ...

  3. 基于 WebSocket 的聊天和大文件上传(有进度提示)完美实现

    大家好,好久没有写文章了,当然不是不想写,主要是工作太忙,公司有没有网络环境,不让上网,所以写的就少了.今天是2019年的最后一天,明天就要开始新的一年,当然也希望自己有一个新的开始.在2019年的最 ...

  4. 洛谷$P2570\ [ZJOI2010]$贪吃的老鼠 网络流+二分

    正解:网络流+二分 解题报告: 传送门$QwQ$ 和上一题有点儿像,,,?$QwQ$但是比上一题要有趣很多$QwQ$ 首先把大致思路捋下?依然是.二分出每个奶酪的开始和结束时间,然后check下最大流 ...

  5. $Poj3017\ Cut\ The\ Sequence$ 单调队列优化$DP$

    Poj   AcWing Description 给定一个长度为N的序列 A,要求把该序列分成若干段,在满足“每段中所有数的和”不超过M的前提下,让“每段中所有数的最大值”之和最小. N<=10 ...

  6. Java入门(三)——集合概讲

    集合(或者叫容器)是Java的核心知识点,它有着很深的深度.我们这里不会设计多深,仅仅作为了解入门,深入了解请移步各种集合源码文章.好的,下面正是开始介绍... Java集合为何而生 我们知道,Jav ...

  7. Python第二天了哇

    在Python中input是接收用户输入的一个函数哇 a = int( b) 这个的意思是把b的值转换为整型? 好像是这个亚子 Python想要知道它的内置函数的话可以在Python的交互界面(She ...

  8. 「洛谷P1196」「NOI2002」银河英雄传说 解题报告

    P1196 [NOI2002]银河英雄传说 题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的 ...

  9. Angular Schematics 三部曲之 Add

    前言 因工作繁忙,差不多有三个月没有写过技术文章了,自八月份第一次编写 schematics 以来,我一直打算分享关于 schematics 的编写技巧,无奈还是拖到了年底. Angular Sche ...

  10. 用TensorFlow做图像识别(python)

    一.TensorFlow简介 TensorFlow是由谷歌开发的一套机器学习的工具,使用方法很简单,只需要输入训练数据位置,设定参数和优化方法等,TensorFlow就可以将优化结果显示出来,节省了很 ...