题解:P10107 [GDKOI2023 提高组] 树

news/2025/9/26 10:29:32/文章来源:https://www.cnblogs.com/LUlululu1616/p/19113010

题意:很简单了,不再赘述。

做法:

题解中好像有很牛的 bfs 序做法,太困难了,我只会暴力还常数很大的长链剖分。

首先看到是个 k 邻域问题,那基本上要不然是 bfs 序转化要不然是长链剖分,我只会后面这个东西所以考虑长链剖分。

然后再看权值,权值是一个异或的形式,那么考虑长链剖分的时候直接向上合并,这样非常麻烦,基本上维护不了异或值的变化,所以考虑拆位,这样我们就可以只用管这一位上的 \(0/1\) 的个数即可。

考虑对于一个节点 \(u\),当前是计算二进制下第 \(k\) 位的答案,他深度中应该是一段长度为 \(2^k\) 的需要权值这一位为 \(1\) 的,一段需要权值这一位为 \(0\) 的去贡献,所以我们长链剖分考虑维护的是 \(u\) 子树中深度为 \(x\)\(0/1\) 有多少个。

如何计算对答案的贡献?显然我们不能暴力一段一段跳往后找,但是我们发现,我们其实可以把一段 0 和一段 1 放在一起计算,也就是说,我们可以记一个 \(f_i\) 代表深度为 \(i\),深度 \(\ge i\) 的异或值这一位为 \(1\) 的有多少个,然后用 \(f_{i} = f_{i+2^{k+1}}+count(i,i+2^k-1, 1)+count(i+2^k,i+2^{k+1}-1,0)\) 去计算,其中 \(count(l,r,x)\) 代表深度在 \([l,r]\) 内有多少个为 \(x\) 的。

计算答案的时候,我们先整段整段按 \(2^{k+1}\) 一个周期地加,这个可以直接用 \(f\) 做减法 \(O(1)\) 得到,然后再用 \(count\) 地方式计算出来散块的贡献。

如何计算 \(count\)?前缀和的话对于我们长链剖分来说太不友好了,合并上来复杂度是长链的,所以我们考虑用后缀和维护就可以了。

有点卡常,一点卡常小技巧:

  1. 不要用 dfs,改成按 dfn 循环。

  2. 不用 vector,什么都别用 vector,不知道为什么特别慢。

  3. 不用维护深度为 \(x\) 的信息,直接维护后缀和就可以了,常数可以减半。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int n, v[maxn], p[maxn], q;
vector<int> e[maxn], qry[maxn];
int mxd[maxn], son[maxn];
void dfs1(int u) {for (int i = 0; i < e[u].size(); i++) {int v = e[u][i];dfs1(v);if(mxd[son[u]] <= mxd[v])son[u] = v;mxd[u] = max(mxd[u], mxd[v] + 1);}
//	cout << u << " " << son[u] << " " << mxd[son[u]] << " " << mxd[u] << endl;
}
int suf[maxn][2];
int id[maxn], tot, bg[maxn], ed[maxn], x[maxn], l[maxn];
long long res[maxn];
inline int cal(int u, int l, int r, int k) {r = min(r, ed[u]);if(l > r)return 0;//cout << u << " " << l << " " << r << " " << suf[u][k][l] << endl;return suf[l][k] - (r == ed[u] ? 0 : suf[r + 1][k]);
}
int ans[maxn], cnt;
vector<int> pos[maxn];
inline void renew(int u, int t, int k) {int mx = 0;//cout << u << " " << val[u][0].size() << " " << id[u] << " " << mxd[7] << endl;for (int i = 0; i < e[u].size(); i++) {int v = e[u][i];if(v == son[u])continue;for (int j = 0; j < mxd[v] + 1; j++)suf[id[u] + j + 1][0] += suf[id[v] + j][0],suf[id[u] + j + 1][1] += suf[id[v] + j][1],ans[id[u] + j + 1] += ans[id[v] + j];mx = max(mx, mxd[v] + 1);}
//	cout << u << endl;if(id[u] != ed[t])suf[id[u]][0] = suf[id[u] + 1][0],suf[id[u]][1] = suf[id[u] + 1][1];suf[id[u]][0] += 1 - ((v[u] >> k) & 1), suf[id[u]][1] += (v[u] >> k) & 1; for (int i = 0; i >= 0; i--) {ans[id[u] + i] = (id[u] + i + (1 << k + 1) > ed[t] ? 0 : ans[id[u] + i + (1 << k + 1)]) + cal(t, id[u] + i, id[u] + i + (1 << k) - 1, 1) + cal(t, id[u] + i + (1 << k), id[u] + i + (1 << k + 1) - 1, 0);}
//	cout << u << " " << ans[id[u]] << " " << k << endl;
}
long long tv[35];
void solve(int k) {if(k == 0) {for (int u = 1; u <= n; u++) {if(son[p[u]] != u) {for (int p1 = u; p1; p1 = son[p1])pos[u].push_back(p1), id[p1] = ++tot;bg[u] = id[u], ed[u] = tot;}}}int cnt = 0;for (int u = n; u >= 1; u--) {if(son[p[u]] == u)continue;for (int i = bg[u]; i <= ed[u]; i++)suf[i][0] = suf[i][1] = ans[i] = 0;//	cout << u << " " << cnt << endl;//	cout << k << " " << u << endl;for (int i = pos[u].size() - 1; i >= 0; i--) {//	cout << i << " adsf" << pos[u][i] << " " << pos[u].size() << endl;renew(pos[u][i], u, k);for (int j = 0; j < qry[pos[u][i]].size(); j++) {int idp = qry[pos[u][i]][j];int kt = (l[idp] >> (k + 1)) << (k + 1), bt = (l[idp] & tv[k + 1]);res[idp] += 1ll * (1 << k) * (ans[id[pos[u][i]]] - ans[id[pos[u][i]] + kt] + (bt >= (1 << k) ? cal(u, bg[u] + i + kt, bg[u] + i + kt + (1 << k) - 1, 1)+ cal(u, bg[u] + i + kt + (1 << k), bg[u] + i + kt + bt, 0) : cal(u, bg[u] + i + kt, bg[u] + i + kt + bt, 1)));}	}
//		for (int i = 0; i < pos[u].size(); i++)
//			cout << suf[bg[u] + i][0] << " ";
//		cout << endl;}
}
int read() {int sum = 0;char c = getchar();while(!isdigit(c))c = getchar();while(isdigit(c))sum = sum * 10 + c - '0', c = getchar();return sum;
}
void write(long long x) {if(x <= 9) {putchar(x + '0');return ;}write(x / 10);putchar(x % 10 + '0');
}
signed main() {
//	freopen("test.in", "r", stdin);
//	freopen("baoli.out", "w", stdout);
//	freopen("P10107_2.in", "r", stdin);
//	freopen("P10107_2.ans", "w", stdout);clock_t st = clock();mxd[0] = -1;n = read();for (int i = 1; i <= n; i++)v[i] = read();for (int i = 2; i <= n; i++)p[i] = read(), e[p[i]].push_back(i);q = read();dfs1(1);for (int i = 1; i <= q; i++)x[i] = read(), l[i] = min(mxd[x[i]], read()), qry[x[i]].push_back(i);// 只做 0 ~ 19 位,更高的没有意义for (int i = 0; i <= 31; i++)tv[i] = (1ll << i) - 1;for (int i = 0; i <= 29; i++) {solve(i);
//		if(i == 0) {
//			for (int j = 0; j < 5; j++)
//				cout << val[1][1][j] << " " << suf[1][1][j] << endl;
//			cout << ans[6] << endl;
//		}}//	cout << ans[pos[1][0]] << " " << pos[1][2] << " " << suf[1][1][2] << " " << cal(1, 3, 3, 0) << endl;//	cout << cnt << endl;
//	cout << tv[31] - tv[20] << endl;cerr << (double)(clock() - st) / CLOCKS_PER_SEC << endl;for (int i = 1; i <= q; i++)write(res[i]), putchar('\n');return 0;
}
/*
7
1 1 1 1 1 1 1
1 1 2 2 3 3
4
1 0
1 1
1 2
2 1
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gitee Wiki:AI赋能的下一代研发知识管理平台如何重塑软件行业协作范式

Gitee Wiki:AI赋能的下一代研发知识管理平台如何重塑软件行业协作范式 在数字化转型浪潮席卷全球的当下,软件研发领域正经历着前所未有的知识管理革命。传统文档管理系统碎片化严重、知识传承断层、安全管控薄弱等问…

COLMAP 安装在ubuntu20服务器上问题解决全记录

系统配置 主机型号:Supermicro SYS-4029GP-TRT2 CPU:Intel Xeon(双路,支持 AVX-512 / OpenMP 4.5) GPU:NVIDIA GPU,CUDA 11.8(驱动对应 515+ 版本) 操作系统:Ubuntu 20.04 LTS 内存:≥ 256 GB 编译器:gcc …

免费带后台的网站模板购物网站开发教学视频

一、接口和抽象类的区别? 方法定义:接口和抽象类,最明显的区别就是接口只是定义了一些方法而已,在不考虑Java8中default方法情况下,接口中只有抽象方法,是没有实现的代码的。(Java8中可以有默认方法) 修饰符:抽象类中的修饰符可以有public、protected和private和<…

完整教程:Prompt Tuning提示词微调工程

完整教程:Prompt Tuning提示词微调工程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mo…

Autodesk Moldflow 2026下载地址与安装教程

软件介绍 Autodesk Moldflow 2026是欧特克公司推出的注塑与压缩成型仿真软件,专为优化塑料产品设计及模具制造流程设计。该版本集成Autodesk Moldflow Data Fitting 2026工具,支持将原始材料数据转换为仿真兼容的.ud…

深入解析:Java SOA集成:从“混乱“到“有序“的3步蜕变之旅!

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

程序员利用Python分析股票赚钱,开发了股票行情看板

近期股市又骚动起来,在3800点附近游荡,回忆起昔日炒股经历,历历在目,悲惨经历让人黯然神伤,去年共投入4000元入市,最后仅剩1000多,当了韭菜,无奈闭关修炼,忘记股市,全身心投入代码世界,享受代码带来的乐趣。…

OcrLicenseVo

public static OcrLicenseVo parseOcrLicense(OcrResultVo item) {int[][][] dtPolyList = new int[9][2][2];for (int i = 0; i < item.getRecTexts().size(); i++) {String value = StringUtils.trimToEmpty(item…

网站设计过程中需要注意的问题安卓开发平台

MBTI简介 迈尔斯-布里格斯类型指标&#xff08;Myers–Briggs Type Indicator&#xff0c;MBTI&#xff09;是由美国作家伊莎贝尔布里格斯迈尔斯和她的母亲凯瑟琳库克布里格斯共同制定的一种人格类型理论模型。 该指标以瑞士心理学家卡尔荣格划分的8种心理类型为基础&#xff…

实用指南:C#上位机软件:1.7 熟悉VS并开启你的第一个C#程序

实用指南:C#上位机软件:1.7 熟悉VS并开启你的第一个C#程序2025-09-26 10:15 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importa…

界面控件DevExpress WinForms v25.1 - AI聊天控件功能持续增强

界面控件DevExpress WinForms v25.1 - AI聊天控件功能持续增强DevExpress WinForms拥有180+组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应…

K8S Deployment 学习

1. Deployment 是什么? Deployment 是 Kubernetes 最常用的控制器之一,用于声明式地管理一组 Pod 副本(通常是无状态应用),实现自动部署、滚动升级、回滚等功能。 它是生产环境推荐的工作负载类型。 底层自动创建…

网站建设与管理专业好找工作吗政务公开 加强门户网站建设

文章目录 前言1.CPU架构2.8086寄存器3. 指令流水线4.内存模型5.总线6.硬盘7 计算机启动过程BIOS8.BootLoader9.地址映射10.为什么boot loader要放在0x7c00这个位置&#xff1f;11 显卡是如何显示的12.汇编指令1.环境搭建 12 程序13 x86 汇编指令介绍 前言 x86汇编 详解x86汇编…

全面掌握 Py2neo 与 Neo4j:从容器化部署到高级应用实战 - 详解

全面掌握 Py2neo 与 Neo4j:从容器化部署到高级应用实战 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Co…

集训队作业1——qoj#11722

Hamilton 解题报告 题目大意 以如下方式给出一张带权无向图:点集为 \(\{1,2,\dots,n\}\),边有两种:\(\forall 1\leq i<n\),\((i,i+1)\) 之间有边权为 \(0\) 的边;\(\forall 1\leq i<j\leq n\) 且 \(\gcd(i,…

US$59 EGS ISN Authorization for CGDI Prog BMW MSV80 Key Programmer

EGS ISN Authorization for CGDI Prog BMW MSV80 Key ProgrammerNo need shipping. Please pass us serial number of your CGDI Prog BMW.Kindly note this authorization is free if you have CGDI Prog MB or CG Pr…

如何设置将浏览器网页临时禁用网页mathjax渲染直接查看latex编译前的文本

如何设置将浏览器网页临时禁用网页mathjax渲染直接查看latex编译前的文本 以上截图来源自网页:https://www.cnblogs.com/brave-light/p/18855706,感谢原作者的分享。

《IDEA 2025破解 长效使用指南:2099 年有效期配置实战之JetBrains全家桶有效》​

一、简介: intellij idea 是一款广泛使用的集成开发环境(ide),专为提高开发者的生产力和代码质量而设计。作为一个强大的多语言 ide,intellij idea 以其智能代码补全、代码分析和重构功能而闻名。intellij idea 提…

网站服务器安装教程视频教程在线制作软件

mars3d开发过程中点击面图层飞行定位&#xff0c;设置俯仰角度后&#xff0c;layer.flyTo({没有生效的排查思路记录&#xff0c;给大家提供一下以后排查定位问题的方向 问题场景相关代码&#xff1a; 1.项目本身代码&#xff1a; 2.精简了关键性代码后&#xff0c;就可以去ge…

手机网站怎么优化关键词在哪查询网站做的哪些外链

目录 引言一、为什么要开发图层顺序调整功能二、开发思路整理1. 拖拽库方案选择2. cesium图层api查询 三、代码编写1. 编写拖拽组件代码2. 修改原有图层管理代码2.1 图层加载移除的调整2.2 图层顺序与拖拽列表的矛盾 3. 编写图层移动代码 四、总结 引言 本教程主要是围绕Cesium…