题意

给出一棵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. Cmder安装与使用

    越来越多人使用Cmder代替Windows的cmd(毕竟其界面太Lower了),但是每次用Cmder都要回到安装目录查找之后才能使用,真的很麻烦,有木有可以像Git一样右键就是可以用的方法呢?答案当然 ...

  2. 学习Java第五周

    通过这一段时间的学习发现Java和C++虽然都是面向对象的编程语言,有相似之处也有不同之处,相似的地方总会感觉易于接受,不同之处或者新接触的有些知识不是很好理解和掌握. 前一段时间学的内部类和接口便是 ...

  3. C++Review1_多态和虚函数

    继承是实现多态的基础.虚函数是实现多态的方法.虚函数.多态.继承都是紧密相关的概念.而继承是所有概念的基础: 多态:简单来讲就是接口一样,实现多样.多态是指通过基类的指针或者引用,在运行时动态调用实际 ...

  4. java 使用 morphia 存取枚举为值

    源码 https://github.com/zhongchengyi/zhongcy.demos/tree/master/mongo-morphia-demo 前言 morphia是java 使用or ...

  5. 玩转MQTT-阿里云之MQTT使用(下)

    玩转MQTT-阿里云之MQTT使用(下) 摘要 为使物联网项目在正式使用时,能顺利切换到具有高并发高负载能力的服务平台,对阿里云提供的MQTT服务进行使用验证. 引言 之前写“MQTT之阿里云使用-玩 ...

  6. 【重学Node.js 第4篇】实现一个简易爬虫&启动定时任务

    实现一个简易爬虫&启动定时任务 课程介绍看这里:https://www.cnblogs.com/zhangran/p/11963616.html 项目github地址:https://gith ...

  7. ansible批量部署mysql

    1.1 将mysql软件包同步到客户端服务器,做安装前期准备 Ps:mysql安装包线拖到ansible服务端的/ansible/roles/mysql/files目录下 vim /ansible/r ...

  8. $Poj2083/AcWing118\ Fractal$ 模拟

    $AcWing$ $Sol$ 一年前做过差不多的南蛮图腾,当时做出来还是很有成就感的$OvO$ $N<=7$,就是模拟模拟,预处理一下,$over$ $Code$ #include<bit ...

  9. Synchronized解析——如果你愿意一层一层剥开我的心

    前言 synchronized,是解决并发情况下数据同步访问问题的一把利刃.那么synchronized的底层原理是什么呢?下面我们来一层一层剥开它的心,就像剥洋葱一样,看个究竟. Synchroni ...

  10. 「学习笔记」珂朵莉树 ODT

    珂朵莉树,也叫ODT(Old Driver Tree 老司机树) 从前有一天,珂朵莉出现了... 然后有一天,珂朵莉树出现了... 看看图片的地址 Codeforces可还行) 没错,珂朵莉树来自Co ...