2018 ACM南京网络赛H题Set解题报告
题目描述
给定\(n\)个数$a_i$,起初第\(i\)个数在第\(i\)个集合。有三种操作(共\(m\)次):
1 $u$ $v$ 将第$u$个数和第$v$个数所在集合合并
2 $u$ 将第$u$个数所在集合所有数加1
3 $u$ $k$ $x$ 问$u$所在集合有多少个数模$2^k$余$x$。
数据范围:\(n,m \le 500000,a_i \le 10^9, 0 \le k \le 30\)。
简要题解
显然此题可以用set加启发式合并在\(O(n \log ^2 n)\)时间复杂度解决本题,但此题时限1.5s,必须使用一个log的做法。事实上,这是一道十分套路的Trie树题目。
首先用并查集维护连通性。
下面先考虑操作3,这相当于询问低$k$位二进制固定时集合中元素个数,可以用Trie树,维护一个子树中终结结点有多少个即可。
对于加1操作,可以在Trie树上打标记,类似线段树进行pushDown标记下传。此题pushDown函数很新颖(之前没写过这样的pushDown),详见代码。(队友指出,此题也可以暴力更新Trie树,至多交换\(\log 10^9\)个结点;不过如果每次加的数不是1的话就必须打标记了。)
对于合并操作,类似线段树合并。由于初始时\(n\)个数共需要\(O(n \log 10^9)\)个结点,而花费O(1)的时间会将总结点数减1,故Trie树合并的总时间复杂度也为\(O(n \log 10^9)\)。关于线段树合并,可以做这道入门题练手:Codeforces Gym 101194G(2016EC Final)
总时间复杂度\(O((n+q) \log 10^9)\)。
注意事项
此题空间复杂度\(O(n \log 10^9)\)。如果Trie树合并使用新开的结点,每个结构体16B,将需要576MB,这会MLE。考虑Trie树合并时不新开结点,可以将空间降至288MB。
完整代码
#include<cstdio>
#include<cstring>
#include<vector>
#define DEPTH 30
using namespace std;
struct Trie{
int size;
int next[];
int tag;
}trie[];
int cnt;
int newTrie(){
memset(&trie[++cnt], , sizeof(Trie));
return cnt;
}
inline void pushDown(int i){
int &t = trie[i].tag;
int &l = trie[i].next[], &r = trie[i].next[];
if (t){
if (t & ){ swap(l, r); trie[l].tag++; }
if (t >= ){ trie[l].tag += t / ; trie[r].tag += t / ; }
t = ;
}
}
inline void pushUp(int i){
trie[i].size = trie[trie[i].next[]].size + trie[trie[i].next[]].size;
}
void insert(int i, int depth, int x)
{
if (!depth){ trie[i].size++; return; }
pushDown(i);
int &pos = trie[i].next[x & ];
if (!pos)pos = newTrie();
insert(pos, depth - , x >> );
pushUp(i);
}
void merge(int& i, int j, int k, int depth)
{
if (j&&k){
i = j;
if (!depth){
trie[i].size += trie[k].size;
return;
}
pushDown(j); pushDown(k);
for (int c = ; c < ; c++)
merge(trie[i].next[c], trie[j].next[c], trie[k].next[c], depth - );
pushUp(i);
}
else i = j ? j : k;
}
int f[], id[];
int getFather(int i)
{
if (f[i] == i)return i;
return f[i] = getFather(f[i]);
}
int main()
{
int n, m, x, u, v, k;
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++){
scanf("%d", &x);
id[i] = newTrie();
f[i] = i;
insert(id[i], DEPTH, x);
}
while (m--){
scanf("%d%d", &x, &u);
u = getFather(u);
if (x == ){
scanf("%d", &v);
v = getFather(v);
if (u != v){
f[u] = v;
merge(id[v], id[u], id[v], DEPTH);
}
}
else if (x == )trie[id[u]].tag++;
else{
scanf("%d%d", &k, &x);
int cur;
for (cur = id[u]; k; k--){
pushDown(cur);
cur = trie[cur].next[x & ];
if (!cur)break;
x >>= ;
}
if (!cur)printf("0\n");
else printf("%d\n", trie[cur].size);
}
}
}
2018 ACM南京网络赛H题Set解题报告的更多相关文章
- 2019ICPC南京网络赛A题 The beautiful values of the palace(三维偏序)
2019ICPC南京网络赛A题 The beautiful values of the palace https://nanti.jisuanke.com/t/41298 Here is a squa ...
- 2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告
2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh ...
- HDU 4758 Walk Through Squares (2013南京网络赛1011题,AC自动机+DP)
Walk Through Squares Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Oth ...
- HDU 4751 Divide Groups (2013南京网络赛1004题,判断二分图)
Divide Groups Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...
- HDU 4750 Count The Pairs (2013南京网络赛1003题,并查集)
Count The Pairs Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others ...
- ACM-ICPC 2018 焦作赛区网络预赛 H题 String and Times(SAM)
Now you have a string consists of uppercase letters, two integers AA and BB. We call a substring won ...
- 无聊的活动/缘生意转(2018 Nova OJ新年欢乐赛B题)解题报告
题目2(下面的太抓 我重新写了个背景 其他都一样) 无聊的活动 JLZ老师不情愿的参加了古风社一年一度的活动,他实在不觉得一群学生跳舞有什么好看,更不明白坐在身后的学生为什么这么兴奋(看小姐姐),于是 ...
- ACM-ICPC 2018青岛网络赛-H题 Traveling on the Axis
题目:略(不知道怎么从ZOJ搬题) 地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4054 把这题的每个点分成两种情况 ...
- 2018南京网络赛L题:Magical Girl Haze(最短路分层图)
题目链接:https://nanti.jisuanke.com/t/31001 解题心得: 一个BZOJ的原题,之前就写过博客了. 原题地址:https://www.lydsy.com/JudgeOn ...
随机推荐
- 安装git 配置邮箱和用户名
git 查看用户名和邮箱地址 $ git config user.email $ git config user.name 运行命令来配置你的用户名和邮箱 $ git config --global ...
- 2018.6.15 Java对象序列化详解
一.定义 Serializable 序列化:把Java对象转换为字节序列的过程. 反序列化:把字节序列恢复为Java对象的过程. ObjectOutputStream对象输出流 可以将实现了Seria ...
- 【luogu P3608 [USACO17JAN]Balanced Photo平衡的照片】 题解
题目链接:https://www.luogu.org/problemnew/show/P3608 乍一看很容易想到O(N^2)的暴力. 对于每个H[i]从i~i-1找L[i]再从i+1~n找R[i], ...
- centos7上mysql8.0rpm方式安装
首先是下载图解 1.首先卸载centos7中自带的mariadb rpm -qa|grep mariadb //查询出来已安装的mariadb rpm -e --nodeps 文件名 //卸载mari ...
- vue.js 图片预览
Vue.js的图片预览的插件还是不少,但是找了半天还是没找到跟现在项目里能用得很顺手的,其实项目里图片预览功能很简单,点击放大,能双指缩放就可以了.部分vue.js的图片预览库都需要把图片资源单独拿出 ...
- php五种常见的设计模式
工厂模式 工厂模式是最常用的实例化对象的模式,是用工厂方法代替new操作的一种模式 使用工厂模式的好处是:如果想要更改实例化的类名,则只需要更改该工厂方法内容即可,不需逐一寻找代码中具体实例化的地方( ...
- python字符编码小结
首先简要说一下各种字符编码: 1. ASCII 计算机只认识0101,但如何让计算机认识人类语言?将每个字母和符号给予固定的编号,然后将这个编号转换成二进制,计算机就可以正确识别这些字母与符号,同时计 ...
- Hive UDAF开发详解
说明 这篇文章是来自Hadoop Hive UDAF Tutorial - Extending Hive with Aggregation Functions:的不严格翻译,因为翻译的文章示例写得比较 ...
- Ping过程&ICMP
1.ICMP(Internet控制消息协议) ICMP=Internet Control Message Protocol 它是TCP/IP协议族的一个子协议 作用:用于在IP主机.路由之间传递控制消 ...
- Android事件分发机制浅析(3)
本文来自网易云社区 作者:孙有军 我们只看最重要的部分 1: 事件为ACTION_DOWN时,执行了cancelAndClearTouchTargets函数,该函数主要清除上一次点击传递的路径,之后执 ...