传送门

考场上觉得复杂度是假的就没怎么优化,然后考完题解帮我证明了它是真的……

首先合并可以用并查集维护,可以顺便维护出集合的大小

对于操作2,发现如果 \(size_i\) 是确定的,可以用权值线段树很方便的维护出合法的 \(size_j\)的个数

每次只需枚举出现过的 \(size_i\) 即可,所以我觉得复杂度是假的

  • 如果存在 \(\sum a_i = n\) ,那么有 \(diff \{a_i\} \leqslant \sqrt n\)

我们有 \(\sum size_i = n\) ,所以不同的size个数只有不超过根号个

所以用个unordered_set维护当前存在的size,线段树查询即可

yysy,我把线段树换成树状数组从1700ms变成了400ms

Code:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define INF 0x3f3f3f3f
  4. #define N 100010
  5. #define ll long long
  6. #define reg register int
  7. //#define int long long
  8. char buf[1<<21], *p1=buf, *p2=buf;
  9. #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
  10. inline int read() {
  11. int ans=0, f=1; char c=getchar();
  12. while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
  13. while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
  14. return ans*f;
  15. }
  16. int n, m;
  17. int fa[N], cnt[N];
  18. bool vis[N];
  19. inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}
  20. namespace force{
  21. void solve() {
  22. for (int i=1; i<=n; ++i) fa[i]=i, cnt[i]=1, vis[i]=1;
  23. ll ans;
  24. for (int i=1,x,y,c,f1,f2; i<=m; ++i) {
  25. if (read()&1) {
  26. x=read(); y=read();
  27. f1=find(x), f2=find(y);
  28. if (f1!=f2) {
  29. cnt[f1]+=cnt[f2];
  30. vis[f2]=0;
  31. fa[f2]=f1;
  32. }
  33. }
  34. else {
  35. ans=0;
  36. c=read();
  37. for (int i=1; i<=n; ++i) if (vis[i])
  38. for (int j=i+1; j<=n; ++j) if (vis[j])
  39. if (abs(cnt[i]-cnt[j])>=c) ++ans;
  40. printf("%lld\n", ans);
  41. }
  42. }
  43. exit(0);
  44. }
  45. }
  46. namespace task1{
  47. int tl[N<<2], tr[N<<2], sum[N<<2];
  48. #define tl(p) tl[p]
  49. #define tr(p) tr[p]
  50. #define sum(p) sum[p]
  51. #define pushup(p) sum(p)=sum(p<<1)+sum(p<<1|1)
  52. void build(int p, int l, int r) {
  53. tl(p)=l; tr(p)=r;
  54. if (l==r) return ;
  55. int mid=(l+r)>>1;
  56. build(p<<1, l, mid);
  57. build(p<<1|1, mid+1, r);
  58. }
  59. void upd(int p, int pos, int dat) {
  60. if (tl(p)==tr(p)) {sum(p)+=dat; return ;}
  61. int mid=(tl(p)+tr(p))>>1;
  62. if (pos<=mid) upd(p<<1, pos, dat);
  63. else upd(p<<1|1, pos, dat);
  64. pushup(p);
  65. }
  66. int query(int p, int l, int r) {
  67. if (l<=tl(p) && r>=tr(p)) return sum(p);
  68. int mid=(tl(p)+tr(p))>>1, ans=0;
  69. if (l<=mid) ans+=query(p<<1, l, r);
  70. if (r>mid) ans+=query(p<<1|1, l, r);
  71. return ans;
  72. }
  73. void solve() {
  74. build(1, 1, n); upd(1, 1, n);
  75. for (int i=1; i<=n; ++i) fa[i]=i, cnt[i]=1, vis[i]=1;
  76. ll ans;
  77. for (int i=1,x,y,c,f1,f2; i<=m; ++i) {
  78. if (read()&1) {
  79. x=read(); y=read();
  80. f1=find(x), f2=find(y);
  81. if (f1!=f2) {
  82. upd(1, cnt[f1], -1); upd(1, cnt[f2], -1);
  83. cnt[f1]+=cnt[f2];
  84. upd(1, cnt[f1], 1);
  85. vis[f2]=0;
  86. fa[f2]=f1;
  87. }
  88. }
  89. else {
  90. ans=0;
  91. c=read();
  92. for (reg i=1,l,r; i<=n; ++i) if (vis[i]) {
  93. if ((l=cnt[i]-c)>=1) ans+=query(1, 1, l)-(c==0);
  94. if ((r=cnt[i]+c+(c==0))<=n) ans+=query(1, r, n);
  95. }
  96. printf("%lld\n", ans/2);
  97. }
  98. }
  99. exit(0);
  100. }
  101. }
  102. namespace task2{
  103. int tl[N<<2], tr[N<<2], sum[N<<2], tot[N], maxn=1;
  104. #define tl(p) tl[p]
  105. #define tr(p) tr[p]
  106. #define sum(p) sum[p]
  107. #define pushup(p) sum(p)=sum(p<<1)+sum(p<<1|1)
  108. void build(int p, int l, int r) {
  109. tl(p)=l; tr(p)=r;
  110. if (l==r) return ;
  111. int mid=(l+r)>>1;
  112. build(p<<1, l, mid);
  113. build(p<<1|1, mid+1, r);
  114. }
  115. void upd(int p, int pos, int dat) {
  116. if (tl(p)==tr(p)) {sum(p)+=dat; return ;}
  117. int mid=(tl(p)+tr(p))>>1;
  118. if (pos<=mid) upd(p<<1, pos, dat);
  119. else upd(p<<1|1, pos, dat);
  120. pushup(p);
  121. }
  122. int query(int p, int l, int r) {
  123. if (l<=tl(p) && r>=tr(p)) return sum(p);
  124. int mid=(tl(p)+tr(p))>>1, ans=0;
  125. if (l<=mid) ans+=query(p<<1, l, r);
  126. if (r>mid) ans+=query(p<<1|1, l, r);
  127. return ans;
  128. }
  129. void solve() {
  130. build(1, 1, n); upd(1, 1, n); tot[1]=n;
  131. for (int i=1; i<=n; ++i) fa[i]=i, cnt[i]=1, vis[i]=1;
  132. ll ans;
  133. for (int i=1,x,y,c,f1,f2; i<=m; ++i) {
  134. if (read()&1) {
  135. x=read(); y=read();
  136. f1=find(x), f2=find(y);
  137. if (f1!=f2) {
  138. upd(1, cnt[f1], -1); upd(1, cnt[f2], -1);
  139. --tot[cnt[f1]]; --tot[cnt[f2]];
  140. cnt[f1]+=cnt[f2];
  141. ++tot[cnt[f1]]; maxn=max(maxn, cnt[f1]);
  142. upd(1, cnt[f1], 1);
  143. vis[f2]=0;
  144. fa[f2]=f1;
  145. }
  146. }
  147. else {
  148. ans=0;
  149. c=read();
  150. for (reg i=1,l,r; i<=maxn; ++i) if (tot[i]) {
  151. if ((l=i-c)>=1) ans+=1ll*tot[i]*(query(1, 1, l)-(c==0));
  152. //cout<<"l: "<<l<<' '<<tot[i]*(query(1, 1, l)-(c==0))<<endl;
  153. if ((r=i+c+(c==0))<=n) ans+=1ll*tot[i]*query(1, r, n);
  154. //cout<<"r: "<<r<<' '<<query(1, r, n)<<endl;
  155. }
  156. printf("%lld\n", ans/2);
  157. }
  158. }
  159. exit(0);
  160. }
  161. }
  162. namespace task{
  163. unordered_set<int> s;
  164. unordered_set<int>::iterator sta[N];
  165. int sum[N], tot[N], top;
  166. inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) sum[i]+=dat;}
  167. inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=sum[i]; return ans;}
  168. void solve() {
  169. upd(1, n); tot[1]=n; s.insert(1);
  170. for (int i=1; i<=n; ++i) fa[i]=i, cnt[i]=1, vis[i]=1;
  171. ll ans;
  172. for (int i=1,x,y,c,f1,f2; i<=m; ++i) {
  173. if (read()&1) {
  174. x=read(); y=read();
  175. f1=find(x), f2=find(y);
  176. if (cnt[f1]<cnt[f2]) swap(f1, f2);
  177. if (f1!=f2) {
  178. upd(cnt[f1], -1); upd(cnt[f2], -1);
  179. --tot[cnt[f1]]; --tot[cnt[f2]];
  180. cnt[f1]+=cnt[f2];
  181. if (++tot[cnt[f1]]==1) s.insert(cnt[f1]);
  182. upd(cnt[f1], 1);
  183. vis[f2]=0;
  184. fa[f2]=f1;
  185. }
  186. }
  187. else {
  188. ans=0;
  189. c=read();
  190. int l, r;
  191. for (unordered_set<int>::iterator it=s.begin(); it!=s.end(); ++it) {
  192. //cout<<"*it: "<<*it<<endl;
  193. if (!tot[*it]) {sta[++top]=it; continue;}
  194. if ((l=*it-c)>=1) ans+=1ll*tot[*it]*(query(l)-(c==0));
  195. //cout<<"l: "<<l<<' '<<tot[i]*(query(1, 1, l)-(c==0))<<endl;
  196. if ((r=*it+c+(c==0))<=n) ans+=1ll*tot[*it]*(query(n)-query(r-1));
  197. //cout<<"r: "<<r<<' '<<query(1, r, n)<<endl;
  198. }
  199. while (top) s.erase(sta[top--]);
  200. printf("%lld\n", ans/2);
  201. }
  202. }
  203. exit(0);
  204. }
  205. }
  206. signed main()
  207. {
  208. n=read(); m=read();
  209. //if (n<=100) force::solve();
  210. //else if (n<=1000) task1::solve();
  211. //else task2::solve();
  212. task::solve();
  213. return 0;
  214. }

题解 Dove 打扑克的更多相关文章

  1. 「10.28」Dove 打扑克(链表)·Cicada 与排序(概率)·Cicada 拿衣服(各种数据结构)

    A. Dove 打扑克 考场思考半天线段树树状数组,没有什么想法 打完暴力后突然想到此题用链表实现会很快. 因为只有$n$堆,所以设最多有$x$个不同的堆数,那么$x\times (x-1)/2==n ...

  2. [UPC10525]:Dove打扑克(暴力+模拟)

    题目描述 $Dove$和$Cicada$是好朋友,他们经常在一起打扑克来消遣时光,但是他们打的扑克有不同的玩法. 最开始时,牌桌上会有$n$个牌堆,每个牌堆有且仅有一张牌,第$i$个牌堆里里里那个扑克 ...

  3. NOIP 模拟 $36\; \rm Dove 打扑克$

    题解 \(by\;zj\varphi\) 引理 对于一个和为 \(n\) 的数列,不同的数的个数最多为 \(\sqrt n\) 证明: 一个有 \(n\) 个不同的数的数列,和最小就是 \(n\) 的 ...

  4. 20210811 Dove 打扑克,Cicada 与排序,Cicada 拿衣服

    考场 开考感觉 T3 比较可做.T1 看上去不难但毫无思路. 先想了 25min T3,想到一个确定左端点,二分最长的右端点,甚至想到了用猫树维护区间 or and...上厕所回来发现假了,没有单调性 ...

  5. 晚间测试13 A. Dove 打扑克 vector +模拟

    题目描述 分析 这道题比较关键的一点就是要看出最终牌数的种类数不会超过 \(\sqrt{n}\) 种 知道了这个性质我们就可以用 \(vector\) 维护一个有序的序列 \(vector\) 中存放 ...

  6. Noip模拟36 2021.8.11

    刚题的习惯还是改不了,怎么办??? T1 Dove打扑克 考场上打的动态开点线段树+并查集,考后发现自己像一个傻子,并查集就行.. 这几天恶补数据结构疯了 用树状数组维护后缀和,$siz_i$表示编号 ...

  7. csp-s模拟测试91

    csp-s模拟测试91 倒悬吃屎的一套题. $T1$认真(?)分析题意发现复杂度不能带$n$(?),计划直接维护答案,考虑操作对答案的影响,未果.突然发现可以动态开点权值线段树打部分分,后来$Tm$一 ...

  8. noip模拟36

    \(\color{white}{\mathbb{荷花映日,莲叶遮天,名之以:残荷}}\) 今天再次翻车掉出前十 开题看错 \(t1\) 以为操作2的值固定发现是个简单题,然后 \(t2\) 开始大力 ...

  9. 2021.8.11考试总结[NOIP模拟36]

    T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...

随机推荐

  1. ESP32-FAT文件系统使用磨损均衡存储文件笔记

    基于ESP-IDF4.1 1 /* 2 FAT文件系统存储文件,使用磨损均衡库wear-leveling 3 */ 4 5 #include <stdlib.h> 6 #include & ...

  2. C语言:赋值流程图

  3. Requests方法 --- post 请求body的四种类型

    常见的 post 提交数据类型有四种: 1.第一种:application/json:这是最常见的 json 格式,也是非常友好的深受小伙伴喜欢的一种,如下{"input1":&q ...

  4. 达梦数据库(DM8)大规模并行集群MPP 2节点安装部署

    达梦数据库大规模并行集群MPP 2节点安装部署   1.环境准备   os 数据库版本 ip mpp角色 centos7.x86 DM8 192.168.30.100 mpp1 centos7.x86 ...

  5. Docker编排利器DockerCompose

    Docker 编排利器 DockerCompose,编排之后可以一次性通过一条命令启动一组服务 例如一条命令启动 SpringBoot 项目,同时启动 SpringBoot 项目依赖的其他中间件(My ...

  6. 基于 apache-arrow 的 duckdb rust 客户端

    背景 duckdb 是一个 C++ 编写的单机版嵌入式分析型数据库.它刚开源的时候是对标 SQLite 的列存数据库,并提供与 SQLite 一样的易用性,编译成一个头文件和一个 cpp 文件就可以在 ...

  7. kafka单机环境配置以及基本操作

    安装地址(已亲测有效):https://www.linuxidc.com/Linux/2019-03/157650.htm

  8. Skywalking-05:在Skywalking RocketBot上添加监控图表

    在 Skywalking RocketBot 上添加监控图表 效果图 该图的一些配置信息如下: 标题为: JVM Thread State Count (Java Service) 指标为: read ...

  9. 如何让py生成pyd

    pyd文件类似于C++中的dll,可以编译,但是看不到源代码. py转换成pyd参考链接:https://blog.csdn.net/weixin_44493841/article/details/1 ...

  10. 并发队列ConcurrentLinkedQueue与LinkedBlockingQueue源码分析与对比

    目录 前言 ConcurrentLinkedQueue 使用方法 存储结构 初始化 入队 出队 获取容器元素数量 LinkedBlockingQueue 使用方法 存储结构 初始化 入队 出队 获取容 ...