Hello world!

题目背景

不远的一年前,小 V 还是一名清华集训的选手,坐在机房里为他已如风中残烛的OI 生涯做最后的挣扎。而如今,他已成为了一名光荣的出题人。他感到非常激动,不禁感叹道: “Hello world!”。

题目描述

小 V 有 \(n\) 道题,他的题都非常毒瘤,所以关爱选手的 ufozgg 打算削弱这些题。为了逃避削弱,小 V 把他的毒瘤题都藏到了一棵 \(n\) 个节点的树里(节点编号从 \(1\) 至 \(n\)),这棵树上的所有节点与小 V 的所有题一一对应。小 V 的每一道题都有一个毒瘤值,节点 \(i\) (表示标号为 \(i\) 的树上节点,下同)对应的题的毒瘤值为 \(a_i\)。

魔法师小 V 为了保护他的题目,对这棵树施了魔法,这样一来,任何人想要一探这棵树的究竟,都必须在上面做跳跃操作。每一次跳跃操作包含一个起点 \(s\) 、一个终点 \(t\) 和一个步频 \(k\) ,这表示跳跃者会从 \(s\) 出发,在树上沿着简单路径多次跳跃到达 \(t\) ,每次跳跃,如果从当前点到 \(t\) 的最短路长度不超过 \(k\) ,那么跳跃者就会直接跳到 \(t\) ,否则跳跃者就会沿着最短路跳过恰好 \(k\) 条边。

既然小 V 把题藏在了树里, ufozgg 就不能直接削弱题目了。他就必须在树上跳跃,边跳跃边削弱题目。 ufozgg 每次跳跃经过一个节点(包括起点 \(s\) ,当 \(s = t\) 的时候也是如此),就会把该节点上的题目的毒瘤值开根并向下取整:即如果他经过了节点 \(i\),他就会使 \(a_i = \lfloor \sqrt{a_i} \rfloor\)。这种操作我们称为削弱操作。

ufozgg 还会不时地希望知道他对题目的削弱程度。因此,他在一些跳跃操作中会放弃对题目的削弱,转而统计该次跳跃经过节点的题目毒瘤值总和。这种操作我们称为统计操作。

吃瓜群众绿绿对小 V 的毒瘤题和 ufozgg 的削弱计划常感兴趣。他现在想知道ufozgg 每次做统计操作时得到的结果。你能帮帮他吗?

输入格式

从文件 helloworld.in 中读入数据。

输入的第一行一个正整数 \(n\) ,表示树的节点数。

接下来一行 \(n\) 个用空格隔开的正整数 \(a_1, a_2, \ldots, a_n\),依次描述每个节点上题目的毒瘤值。

接下来 \(n − 1\) 行,描述这棵树。每行 \(2\) 个正整数 \(u, v\) ,描述一条树上的边 \((u, v)\) 。(保证 \(1 \leq u, v \leq n\) ,保证这 \(n − 1\) 条边构成了一棵树)

接下来一行一个正整数 \(Q\) ,表示 ufozgg 的操作总数。

接下来 \(Q\) 行按 ufozgg 执行操作的先后顺序依次描述每个操作,每行 \(4\) 个用空格隔开的整数 \(op, s, t, k\) ,表示 ufozgg 此次跳跃的起点为 \(s\) ,终点为 \(t\) ,步频为 \(k\) 。如果 \(op = 0\) ,表示这是一次削弱操作;如果 \(op = 1\) ,表示这是一次统计操作。

输出格式

对于每个统计操作,输出一行一个整数,表示此次统计操作统计到的所有题的毒瘤值总和。

样例 #1

样例输入 #1

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

样例输出 #1

10
8 6 5

提示

对于 \(100\%\) 的数据,\(n≤50000\), \(Q≤400000\), \(1\leq ai\leq 10^{13}\)。

对于所有的操作保证 \(0\leq op\leq 1\),\(1\leq s,t,k\leq n\)。

引入:

维护一个数据结构支持单点修改,链求和。这个是可以不用树剖的。可以维护一个点到根之和,修改时相当于子树加,链求和可以差分。所以用树状数组维护 dfs 序就可以了。

走 \(k\),步,一个很经典的根号分治的线索。

预处理长剖 \(k\) 级祖先,所有询问都可以在 \(O(\frac{nQ}k)\) 的复杂度以内完成。可以先把 \(t\) 向上跳 \(dis(s,t)\bmod k\) 步,然后 \(s\) 和 \(t\) 一起往上 \(k\) 步的跳。

然后考虑把 \(k\) 比较小的情况维护出来。先看修改,首先一个点开根 \(\log\log a\) 次之后就会变成 1。可以用并查集维护一个点向上跳 \(k\) 步,第一个不为 1 的在哪里。然后我们就可以用引入的内容维护所有的 \(k\) 步,维护 \(dep mod k\) 这条链之和。查询时直接询问链就行了。

如果对 \(B\) 以内的 \(k\) 这样预处理复杂度就是 \(nB\log\log A\log n\)

然后

B 取 \(\sqrt{\frac Q{\log\log a\log n}}\) 时,复杂度取到最优值。但是实测时 B 取 25 最好(常数小?)

#include<bits/stdc++.h>
using namespace std;
const int N=50005,B=25;
typedef long long LL;
int n,fa[B][N],f[N][20],ln[N],son[N],q,in[B][N],out[B][N],top[N],dep[N],lg[N],c;
LL ans,a[N];
vector<int>u[N],d[N],g[N];
vector<LL>tr[B][B];
void upd(int k,int p,int x,LL y)
{
for(int i=x;i<tr[k][p].size();i+=i&-i)
tr[k][p][i]+=y;
}
void sou(int x,int y)
{
f[x][0]=y;
dep[x]=dep[y]+1;
for(int i=1;i<B;i++)
{
in[i][x]=tr[i][dep[x]%i].size();
tr[i][dep[x]%i].push_back(0);
}
for(int i=1;i<20;i++)
f[x][i]=f[f[x][i-1]][i-1];
for(int v:g[x])
{
if(v==y)
continue;
sou(v,x);
if(ln[v]+1>ln[x])
ln[x]=ln[v]+1,son[x]=v;
}
for(int i=1;i<B;i++)
out[i][x]=tr[i][dep[x]%i].size();
}
void dfs(int x,int y,int tp)
{
d[tp].push_back(x);
if(son[x])
dfs(son[x],x,tp);
top[x]=tp;
for(int v:g[x])
if(v^y&&v^son[x])
dfs(v,x,v);
if(x==tp)
{
int y=x;
for(int i=0;i<=ln[x]&&y;i++)
{
u[x].push_back(y);
y=f[y][0];
}
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])
swap(x,y);
while(dep[x]>dep[y])
x=f[x][lg[dep[x]-dep[y]]];
if(x==y)
return x;
for(int i=19;~i;--i)
if(f[x][i]^f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int ask(int x,int k)
{
if(!k)
return x;
int p=x,q=lg[k];
assert(dep[x]-k>0);
x=f[x][lg[k]];
assert(x);
k-=1<<lg[k];
if(dep[x]-dep[top[x]]<=k)
return u[top[x]][k-dep[x]+dep[top[x]]];
return d[top[x]][dep[x]-dep[top[x]]-k];
}
int find(int k,int x)
{
if(fa[k][x]==x)
return x;
return fa[k][x]=find(k,fa[k][x]);
}
void upd(int x)
{
if(a[x]==1)
return;
LL t=sqrt(a[x]);
assert(t*t<=a[x]);
while((t+1)*(t+1)<a[x])
++t;
for(int i=1;i<B;i++)
{
upd(i,dep[x]%i,in[i][x],t-a[x]);
upd(i,dep[x]%i,out[i][x],a[x]-t);
}
a[x]=t;
if(a[x]==1)
for(int i=1;i<B&&i<dep[x];i++)
fa[i][x]=find(i,ask(x,i));
}
LL query(int k,int x)
{
int d=dep[x]%k,p=in[k][x];
LL ans=0;
for(;p;p-=p&-p)
ans+=tr[k][d][p];
return ans;
}
int main()
{
for(int i=2;i<N;i++)
lg[i]=lg[i>>1]+1;
for(int i=0;i<B;i++)
{
for(int j=0;j<B;j++)
tr[i][j].push_back(0);
for(int j=1;j<N;j++)
fa[i][j]=j;
}
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",a+i);
for(int i=1,u,v;i<n;i++)
scanf("%d%d",&u,&v),g[u].push_back(v),g[v].push_back(u);
sou(1,0);
dfs(1,0,1);
for(int i=1;i<B;i++)
for(int j=1;j<=n;j++)
if(a[j]==1&&i<dep[j])
fa[i][j]=find(i,ask(j,i));
for(int i=1;i<B;i++)
for(int j=1;j<=n;j++)
upd(i,dep[j]%i,in[i][j],a[j]),upd(i,dep[j]%i,out[i][j],-a[j]);
scanf("%d",&q);
while(q--)
{
int op,s,t,k,d;
scanf("%d%d%d%d",&op,&s,&t,&k);
d=lca(s,t);
int g=(dep[s]+dep[t]-2*dep[d])%k;
if(op)
{
ans=a[t]+a[s];
if(g&&dep[t]-g>=dep[d])
{
t=ask(t,g);
ans+=a[t];
}
if(k>=B)
{
while(dep[s]-k>=dep[d])
{
s=ask(s,k);
ans+=a[s];
}
while(dep[t]-k>=dep[d])
{
t=ask(t,k);
ans+=a[t];
}
}
else
{
if(dep[s]-k>=dep[d])
{
int u=(dep[d]-dep[s]%k+k)%k;
if(!u)
u=k;
ans+=query(k,ask(s,k));
if(dep[d]>u)
ans-=query(k,ask(d,u));
}
if(dep[t]-k>=dep[d])
{
int u=(dep[d]-dep[t]%k+k)%k;
if(!u)
u=k;
ans+=query(k,ask(t,k));
if(dep[d]>u)
ans-=query(k,ask(d,u));
}
}
if(dep[d]%k==dep[s]%k)
ans-=a[d];
printf("%lld\n",ans);
++c;
}
else
{
if(g&&dep[t]-g>dep[d])
{
upd(t);
t=ask(t,g);
}
if(d^t)
upd(t);
if(d^s)
upd(s);
if(k>=B)
{
while(dep[s]-k>dep[d])
{
s=ask(s,k);
upd(s);
}
while(dep[t]-k>dep[d])
{
t=ask(t,k);
upd(t);
}
}
else
{
while(dep[s]-k>dep[d])
{
s=find(k,ask(s,k));
if(dep[s]>dep[d])
upd(s);
}
while(dep[t]-k>dep[d])
{
t=find(k,ask(t,k));
if(dep[t]>dep[d])
upd(t);
}
}
if(dep[s]%k==dep[d]%k||t==d)
upd(d);
}
}
}

[清华集训2017] Hello World!的更多相关文章

  1. Loj #2331. 「清华集训 2017」某位歌姬的故事

    Loj #2331. 「清华集训 2017」某位歌姬的故事 IA 是一名会唱歌的女孩子. IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿.这首歌一共有 \(n\) 个音符, ...

  2. Loj #2324. 「清华集训 2017」小 Y 和二叉树

    Loj #2324. 「清华集训 2017」小 Y 和二叉树 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上, ...

  3. Loj #2321. 「清华集训 2017」无限之环

    Loj #2321. 「清华集训 2017」无限之环 曾经有一款流行的游戏,叫做 *Infinity Loop***,先来简单的介绍一下这个游戏: 游戏在一个 \(n \times m\) 的网格状棋 ...

  4. Loj 2320.「清华集训 2017」生成树计数

    Loj 2320.「清华集训 2017」生成树计数 题目描述 在一个 \(s\) 个点的图中,存在 \(s-n\) 条边,使图中形成了 \(n\) 个连通块,第 \(i\) 个连通块中有 \(a_i\ ...

  5. 【UOJ#340】【清华集训2017】小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划)

    [UOJ#340][清华集训2017]小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划) 题面 UOJ 洛谷 题解 考虑如何暴力\(dp\). 设\(f[i][a][b][c]\)表示当前到了第\(i\) ...

  6. loj #2325. 「清华集训 2017」小Y和恐怖的奴隶主

    #2325. 「清华集训 2017」小Y和恐怖的奴隶主 内存限制:256 MiB时间限制:2000 ms标准输入输出 题目类型:传统评测方式:文本比较   题目描述 "A fight? Co ...

  7. [LOJ#2330]「清华集训 2017」榕树之心

    [LOJ#2330]「清华集训 2017」榕树之心 试题描述 深秋.冷风吹散了最后一丝夏日的暑气,也吹落了榕树脚下灌木丛的叶子.相识数年的Evan和Lyra再次回到了小时候见面的茂盛榕树之下.小溪依旧 ...

  8. [LOJ#2329]「清华集训 2017」我的生命已如风中残烛

    [LOJ#2329]「清华集训 2017」我的生命已如风中残烛 试题描述 九条可怜是一个贪玩的女孩子. 这天她在一堵墙钉了 \(n\) 个钉子,第 \(i\) 个钉子的坐标是 \((x_i,y_i)\ ...

  9. [LOJ#2328]「清华集训 2017」避难所

    [LOJ#2328]「清华集训 2017」避难所 试题描述 "B君啊,你当年的伙伴都不在北京了,为什么你还在北京呢?" "大概是因为出了一些事故吧,否则这道题就不叫避难所 ...

  10. [LOJ#2327]「清华集训 2017」福若格斯

    [LOJ#2327]「清华集训 2017」福若格斯 试题描述 小d是4xx9小游戏高手. 有一天,小d发现了一个很经典的小游戏:跳青蛙. 游戏在一个 \(5\) 个格子的棋盘上进行.在游戏的一开始,最 ...

随机推荐

  1. Qt安卓开发经验技巧总结V202308

    01:01-05 pro中引入安卓拓展模块 QT += androidextras . pro中指定安卓打包目录 ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android ...

  2. 使用 KubeBlocks 为 K8s 提供稳如老狗的数据库服务

    原文链接:https://forum.laf.run/d/994 大家好!今天这篇文章主要向大家介绍 Sealos 的数据库服务.在 Sealos 上数据库后端服务由 KubeBlocks 提供,为用 ...

  3. 在本地运行Kusto服务器

    我喜欢Kusto (或商用版本 Azure Data Explorer,简称 ADX) 是大家可以有目共睹的,之前还专门写过这方面的书籍,请参考 大数据分析新玩法之Kusto宝典, 很可能在今年还会推 ...

  4. springboot整合seata1.5.2+nacos2.1.1

    一.前言 Seata出现前,大部分公司使用的都是TCC或者MQ(RocketMq)等来解决分布式事务的问题,TCC代码编写复杂,每个业务均需要实现三个入口,侵入性强,RocketMQ保证的是最终一致性 ...

  5. 请大家一定不要像我们公司这样打印log日志

    前言 最近接手了公司另一个项目,熟悉业务和代码苦不堪言. 我接手一个新项目,有个习惯,就是看结构,看数据库,搜代码. 其中搜代码是我个人这些年不知不觉形成的癖好,我下面给大家展示下这个小癖好. 正文 ...

  6. 【RocketMQ】消息的拉取总结

    在上一讲中,介绍了消息的存储,生产者向Broker发送消息之后,数据会写入到CommitLog中,这一讲,就来看一下消费者是如何从Broker拉取消息的. RocketMQ消息的消费以组为单位,有两种 ...

  7. LeetCode 周赛上分之旅 #49 再探内向基环树

    ️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问. 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越 ...

  8. Python基础——垃圾回收、格式化输入输出、基本运算符、流程控制

    文章目录 每日测验 垃圾回收机制详解(了解) 引用计数 标记清除 分代回收 与用户交互 接收用户的输入 字符串的格式化输出 填充与格式化 基本运算符 算数运算符 比较运算符: >.>=.& ...

  9. C# 12 中的新增功能

    新的 C# 12 功能在预览版中已经引入. 您可以使用最新的 Visual Studio 预览版或最新的 .NET 8 预览版 SDK 来尝试这些功能.以下是一些新引入的功能: 主构造函数 集合表达式 ...

  10. 如何用ppt打印9张一面,并且去除边距?

    如何用ppt打印9张一面,并且去除边距?      方法其实很简单,答主不要在ppt软件的打印选项里设置[每页打印9张幻灯片],而是使用默认的[每页打印1张幻灯片]. 然后去[打印机属性]里设置,我是 ...