题意

给出一棵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. Channel 9视频整理【2】

    JadeChang https://channel9.msdn.com/Niners/JadeChang 繁体中文视频 2016 Nano Server / Docker / Containers 打 ...

  2. 33.python之操作系统,进程,线程

    转载:https://www.cnblogs.com/yuanchenqi/articles/6248025.html 操作系统 一 为什么要有操作系统? 现代计算机系统是由一个或者多个处理器,主存, ...

  3. spring整合springMVC、mybatis、shiro

    jar包: <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding& ...

  4. 洛谷$P$2518 计数 $[HAOI2010]$ 数位$dp$

    正解:数位$dp$ 解题报告: 传送门$w$ 感觉省选的数位$dp$还是比较有质量的辣,,,至少有一定的思维难度是趴$QwQ$ 这题要考虑到一个,我认为比较关键的点,就,对于一个位数不满的数,可以理解 ...

  5. 聊聊Python中的描述符

    描述符是实现描述符协议方法的Python对象,当将其作为其他对象的属性进行访问时,该描述符使您能够创建具有特殊行为的对象. 通常,描述符是具有“绑定行为”的对象属性,其属性访问已被描述符协议中的方法所 ...

  6. Nginx 究竟如何处理事件?

    在了解了网络事件以及事件分发收集器以后,让我们来了解 Nginx 是怎么样处理事件的? Nginx 事件循环 当 Nginx 刚刚启动时,在等待事件部分,也就是打开了 80 或 443 端口,这个时候 ...

  7. 「Luogu P3395」路障 解题报告

    点开有惊喜 其实是题面 这D1T1给的很有面子! 我居然做的来! 从左上角走到右上角 然后n<=1000 所以果断放弃DFS,选择BFS 思路还是一样的BFS 证明: 走到一个点的时间越早越好( ...

  8. 类加载器在Tomcat中的应用

    之前有文章已经介绍过了JVM中的类加载机制,JVM中通过类加载加载class文件,通过双亲委派模型完成分层加载.实际上类加载机制并不仅仅是在JVM中得以运用,通过影响字节码生成和类加载器目前已经有了许 ...

  9. 下载并部署 ArcGIS API for JavaScript 4.10

    学习ArcGIS API for JavaScript 4.10 的第一步就是下载并部署该文件. 有的读者由于之间没接触过,不知道怎么下载和部署文件.这些读者要求作者详细的写一篇关于下载和部署的文章( ...

  10. cogs 1588. [USACO Feb04]距离咨询 倍增LCA

    1588. [USACO Feb04]距离咨询 ★★   输入文件:dquery.in   输出文件:dquery.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 农夫 ...