简单数据结构题(from 钟子谦——IOI2018集训队自选题)
简单数据结构题(from 钟子谦——IOI2018集训队自选题)
试题描述
给一棵 \(n\) 个点的树,点权开始为 \(0\) ,有 \(q\) 次操作,每次操作是选择一个点,把周围一圈点点权 \(+1\)(一个点周围的点为与该点距离为 \(1\) 的点),在该操作后你需要输出当前周围一圈点点权的异或和。
由于输出量较大,设第 \(i\) 个询问输出为 \(ans_i\),你只需要输出
\begin{equation}
[\sum^q_{i=1}ans_i \cdot (i^2+i)] \texttt{ mod } (10^9+7)
\notag
\end{equation}
输入
第一行两个数 \(n\) , \(q\) ,表示树的点数和操作数。
接下来 \(n-1\) 行每行两个数表示树上的一条边。
接下来 \(q\) 行每行一个数 \(x\),表示把 \(x\) 周围一圈点点权 \(+1\)。
输出
输出一个 \([0,10^9+7)\) 的数,详见题目描述。
输入示例
5 10
1 2
2 3
2 4
3 5
1
5
2
4
3
5
4
2
3
1
输出示例
2060
数据规模及约定
对于 \(80\texttt{%}\) 的数据,保证 \(n = 1000\)
对于 \(90\texttt{%}\) 的数据,保证 \(n = 100000\)
对于 \(100\texttt{%}\) 的数据,保证 \(n = 500000\)
题解
这题差最后一步想到了。
不过好像除了 trie 树这步最妙这题也没其他什么了。。。
每个点周围的点可以分为父节点和子树中的一层节点,所以我们可以把一个节点 \(u\) 的所有儿子的信息存储到节点 \(u\) 中,然后对于一个询问,父亲单独计算,统一计算所有儿子的。
所以现在要一个可以支持删除、插入(对父亲的单独操作)、全体加 \(1\)、求全体异或和的数据结构。
一个数 \(x\) 加上 \(1\) 可以看做 \(x \rightarrow x \bigoplus (2 \cdot lowbit(\texttt{~}x) - 1)\)(\(\bigoplus\) 表示异或运算符,\(\texttt{~}\) 表示取反运算符,\(lowbit(t)\) 表示只取 \(t\) 最低位的 \(1\)),所以我们需要维护集合内所有 \(x\) 的同时维护所有的 \(lowbit(\texttt{~}x)\),确切地,只需要知道每种 \(lowbit(x)\)(最多 \(\log q\) 种)的取值有多少个。
然后就是我没想到的最后一步了:建立 trie 树保存集合内所有数(从浅到深按从低位到高位的顺序保存),\(lowbit(\texttt{~}x)\) 很好得到了,然后全体 \(+1\) 就是每次交换左右子树,然后递归到左子树去(即最低位异或 \(1\) 然后处理进位)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 500010
#define maxm 1000010
#define maxnode 10000010
#define maxlog 25
#define MOD 1000000007
#define LL long long
int n, m, head[maxn], nxt[maxm], to[maxm], Fa[maxn], at[maxn];
int ToT, rt[maxn], val[maxnode], ch[maxnode][2], siz[maxnode], fa[maxnode], rec[maxlog], cntr;
void AddEdge(int a, int b) {
to[++m] = b; nxt[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; nxt[m] = head[a]; head[a] = m;
return ;
}
int getnode() {
int u;
if(cntr) u = rec[cntr--];
else u = ++ToT;
ch[u][0] = ch[u][1] = fa[u] = siz[u] = 0;
return u;
}
int Insert(int& r, int v) {
if(!r) r = getnode(), val[r] = v;
else val[r] ^= v;
int u = r; siz[u]++;
rep(i, 1, 20) {
int x = v & 1; v >>= 1;
if(!ch[u][x]) fa[ch[u][x] = getnode()] = u;
u = ch[u][x]; siz[u]++;
}
// printf("Insert(%d): %d\n", r, u);
return u;
}
void build(int u) {
rt[u] = ++ToT;
for(int e = head[u]; e; e = nxt[e]) if(to[e] != Fa[u]) {
at[to[e]] = Insert(rt[u], 0);
Fa[to[e]] = u;
build(to[e]);
}
return ;
}
int getnum(int u) {
int res = 0; cntr = 0;
while(u) {
if(fa[u] && ch[fa[u]][1] == u) res = res << 1 | 1;
else if(fa[u]) res <<= 1;
// printf("getnum: %d\n", u);
siz[u]--;
if(!siz[u] && fa[u]) {
rec[++cntr] = u;
// printf("recycle %d\n", u);
if(ch[fa[u]][1] == u) ch[fa[u]][1] = 0;
else ch[fa[u]][0] = 0;
}
if(!fa[u]) val[u] ^= res;
u = fa[u];
}
return res;
}
void Add(int r) {
int u = r, d = 0;
while(u) {
int s = ch[u][0] ? siz[ch[u][0]] : 0;
if(!ch[u][1]) s = siz[u];
if(s & 1) val[r] ^= (1 << d + 1) - 1;
u = ch[u][1]; d++;
}
u = r;
while(u) {
swap(ch[u][0], ch[u][1]);
u = ch[u][0];
}
return ;
}
int main() {
n = read(); int q = read();
rep(i, 1, n - 1) {
int a = read(), b = read();
AddEdge(a, b);
}
Insert(rt[0], 0);
build(1);
int Ans = 0;
rep(i, 1, q) {
int u = read(), ans = 0;
if(Fa[u]) {
ans = getnum(at[Fa[u]]) + 1;
// printf("faans: %d\n", ans);
at[Fa[u]] = Insert(rt[Fa[Fa[u]]], ans);
}
// printf("beforeAdd: %d\n", val[rt[u]]);
Add(rt[u]);
ans ^= val[rt[u]];
// printf("afterAdd: %d\n", val[rt[u]]);
(Ans += (LL)ans * ((LL)i * i % MOD + i) % MOD) %= MOD;
}
printf("%d\n", Ans);
return 0;
}
简单数据结构题(from 钟子谦——IOI2018集训队自选题)的更多相关文章
- test20191210 钟子谦
100+40+0=140.暴力没写满-- 简单模拟 很久很久以前,有一个 \(1\sim n\) 的排列 \(a\),还有一个长度为 \(q\) 的,每个元素在 \(1\) 到 \(n\) 之间的序列 ...
- [Contest20171102]简单数据结构题
给一棵$n$个点的数,点权开始为$0$,有$q$次操作,每次操作选择一个点,把周围一圈点点权$+1$,在该操作后你需要输出当前周围一圈点点权的异或和. 由于输出量较大,设第$i$个询问输出为$ans_ ...
- ioi2018集训队自选题:最短路练习题
题意:链接 定义pos[i]表示i这个值在数组里的下标. 我们先用单调栈找到每个元素左边和右边第一个比它大的元素$l_i$和$r_i$,然后建一棵二叉树,我们就叫做maxtree吧 (upd:mdzz ...
- QDUOJ 一道简单的数据结构题 栈的使用(括号配对)
一道简单的数据结构题 发布时间: 2017年6月3日 18:46 最后更新: 2017年6月3日 18:51 时间限制: 1000ms 内存限制: 128M 描述 如果插入“+”和“1”到 ...
- [LOJ#2326]「清华集训 2017」简单数据结构
[LOJ#2326]「清华集训 2017」简单数据结构 试题描述 参加完IOI2018之后就是姚班面试.而你,由于讨厌物理.并且想成为乔布斯一样的创业家,被成功踢回贵系. 转眼,时间的指针被指向201 ...
- 2019浙大校赛--A--Thanks, TuSimple!(简单模拟题)
这题前三段都是一堆吹爆赞助商的屁话,正式题目在图片下边,一个简单模拟题. 题目大意: 有n个男生,m个女生在进行舞会,其中一部分男生祥和比自己矮的女生跳舞,一部分男生想和比自己高的女生跳舞,一部分女生 ...
- 【Luogu3676】小清新数据结构题(动态点分治)
[Luogu3676]小清新数据结构题(动态点分治) 题面 洛谷 题解 先扯远点,这题我第一次看的时候觉得是一个树链剖分+线段树维护. 做法大概是这样: 我们先以任意一个点为根,把当前点看成是一棵有根 ...
- python学习总结----简单数据结构
mini-web服务器 - 能够完成简单的请求处理 - 使用http协议 - 目的:加深对网络编程的认识.为后面阶段学习web做铺垫 简单数据结构 - 排列组合 import itertools # ...
- 牛客练习赛22-E.简单数据结构1(扩展欧拉定理降幂 +树状数组)
链接:E.简单数据结构1 题意: 给一个长为n的序列,m次操作,每次操作: 1.区间加 2.对于区间,查询 ,一直到- 请注意每次的模数不同. 题解:扩展欧拉定理降幂 对一个数p取log(p)次的 ...
随机推荐
- 如何在python中读写和存储matlab的数据文件(*.mat)
使用sicpy.io即可.sicpy.io提供了两个函数loadmat和savemat,非常方便. 以前也有一些开源的库(pymat和pymat2等)来做这个事, 不过自从有了numpy和scipy以 ...
- Oracle数据库学习(四)
11.创建表 crate table tab1(f_id number not null,f_a varchar2(7) not null,f_b number(6,2) not null): 主键: ...
- SummerVocation_Learning--StringBuffer类
java.lang.StringBuffer代表可变的字符序列.与String类基本类似. 常见的构造方法: StringBuffer(),创建一个不包含字符序列的空的StringBuffer对象. ...
- cf550D. Regular Bridge(构造)
题意 给出一个$k$,构造一个无向图,使得每个点的度数为$k$,且存在一个桥 Sol 神仙题 一篇写的非常好的博客:http://www.cnblogs.com/mangoyang/p/9302269 ...
- Java - 网络
要事为先,你如果想要在这个行业发展下去的话,实际上三角形的三个点在支撑着你发展,一个是技术.一个是管理(不是说管理别人,是管理你自己的时间,管理你自己的精力).还有一个就是沟通,注重这三点均衡的发展. ...
- Ubuntu16.04 hadoop 伪分布式 的文件配置
首先需要完成java环境的配置,这里就省略了. 完成 hadoop 伪分布(pesudo distribution),只需配置下面 五 个文件即可: hadoop-env.sh core-site.x ...
- linux 服务器被植入ddgs、qW3xT.2挖矿病毒处理记录
被入侵后的现象: 发现有qW3xT.2与ddgs两个异常进程,消耗了较高的cpu,kill掉后 过一会就会重新出现. kill 掉这两个异常进程后,过一段时间看到了如下进程: 首先在/etc/sysc ...
- python3+openCV实现图片的人脸人眼检测,原理+参数+源代码
上学时候用matlab学过一些图像处理的基础知识,当时课程作业是用haar实现人脸检测 but当时是心思根本不在图像处理上,so找了个同学帮忙做的,自己没上心 然鹅天道好轮回,现在捡起来了原来的算法一 ...
- django之模型层
1. ORM MVC或者MTV框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员 ...
- libevent 信号事件实现方式
学会使用libevent,才能真正的掌握其是实现原理,我们先从一个简短的测试用例开始: #include <sys/types.h> #include <sys/stat.h> ...