「YNOI2016」自己的发明

不换根

基本的莫队吧...

子树直接转到dfs序上。

其余部分可以见 「SNOI2017」一个简单的询问

换根

根root,查询x,分3种:

  1. root不在x子树内,按照原来dfs序区间即可
  2. root在x子树内且root!=x,那么就是整个序列除掉H(root的祖先,且为x儿子)对应的dfs序区间
  3. root=x

直接将序列扩展就可以了,常数共\(8 \sqrt 2\)。

优化

若H对应区间为\([l,r]\)时,那么答案为\(cnt[1,l-1] + cnt[r+1,n]=(cnt[1,n]-cnt[l,r])\),再乘上另一个区间。

那么可以预处理出\([1,x]\)与\([1,n]\)的答案。

这样每个询问只需要做一次\([l,r]\)和\([l1,r1]\)的查询了,常数4。

但是,实际上不没有快多少...


对2e6个询问排序,复杂度极高。

因此,可以用vector存每个左端点块对应询问,再排序。

效果明显(!


倍增过程可以去掉,每个点用vector存儿子dfn序,若将子树中某点跳到该点的某个儿子,可以在该点直接二分一下。

只快了一点...

  1. #include <bits/stdc++.h>
  2. #define rep(q, a, b) for (int q = a, q##_end_ = b; q <= q##_end_; ++q)
  3. #define dep(q, a, b) for (int q = a, q##_end_ = b; q >= q##_end_; --q)
  4. #define mem(a, b) memset(a, b, sizeof a)
  5. #define debug(a) cerr << #a << ' ' << a << "___" << endl
  6. using namespace std;
  7. bool cur1;
  8. char buf[10000000], *p1 = buf, *p2 = buf;
  9. #define Getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 10000000, stdin), p1 == p2) ? EOF : *p1++
  10. void in(int &r) {
  11. static char c;
  12. r = 0;
  13. while (c = Getchar(), c < 48)
  14. ;
  15. do
  16. r = (r << 1) + (r << 3) + (c ^ 48);
  17. while (c = Getchar(), c > 47);
  18. }
  19. const int mn = 100005;
  20. const int mm = 500005;
  21. int K, n, m, vl[mn], val[mn];
  22. int head[mn], ne[mn << 1], to[mn << 1], cnt2;
  23. #define link(a, b) link_edge(a, b), link_edge(b, a)
  24. #define link_edge(a, b) to[++cnt2] = b, ne[cnt2] = head[a], head[a] = cnt2
  25. #define travel(x) for (int q(head[x]); q; q = ne[q])
  26. int ind, dfn_l[mn], dfn_r[mn];
  27. vector<int> son[mn];
  28. int mp[mn];
  29. void dfs(int f, int x) {
  30. ++ind, mp[ind]=x,val[ind] = vl[x], dfn_l[x] = ind;
  31. travel(x) if (to[q] != f) dfs(x, to[q]),son[x].push_back(dfn_l[to[q]]);
  32. dfn_r[x] = ind;
  33. }
  34. int get_high(int x, int v) {
  35. int l=0,r=(int)son[x].size()-1,ans=0;
  36. while(l<=r){
  37. int mid=l+r>>1;
  38. if(son[x][mid]>v)r=mid-1;
  39. else l=mid+1,ans=mid;
  40. }
  41. return mp[son[x][ans]];
  42. }
  43. long long ans[mm];
  44. struct node {
  45. int l, r, id;
  46. inline bool operator<(const node &A) const { return r < A.r; }
  47. };
  48. inline bool cmp(node a, node b) { return a.r > b.r; }
  49. vector<node> an[800];
  50. int cnt[mn], cnt1[mn];
  51. bool mark[mm];
  52. long long mid_ans, mid[mn];
  53. void init() {
  54. dfs(0, 1);
  55. sort(mid + 1, mid + n + 1);
  56. rep(q, 1, n) val[q] = lower_bound(mid + 1, mid + n + 1, val[q]) - mid;
  57. rep(q, 1, n)++ cnt[val[q]];
  58. rep(q, 1, n) mid[q] = mid[q - 1] + cnt[val[q]];
  59. rep(q, 1, n)-- cnt[val[q]];
  60. }
  61. int find(int rt, int x) {
  62. if (dfn_l[rt] >= dfn_l[x] && dfn_l[rt] <= dfn_r[x])
  63. return get_high(x, dfn_l[rt]);
  64. return 0;
  65. }
  66. bool cur2;
  67. int main() {
  68. // cerr<<(&cur2-&cur1)/1024.0/1024<<endl;
  69. int td, l, r, l1, r1;
  70. in(n), in(m);
  71. rep(q, 1, n) in(vl[q]), mid[q] = vl[q];
  72. rep(q, 2, n) in(l), in(r), link(l, r);
  73. init();
  74. K = n / sqrt(m)*1.2 + 1;
  75. int rt = 1;
  76. rep(q, 1, m) {
  77. in(td);
  78. if (td == 1)
  79. in(rt);
  80. else {
  81. mark[q] = 1;
  82. in(l), in(l1);
  83. if (rt == l || rt == l1) {
  84. if (rt == l1)
  85. swap(l, l1);
  86. if (rt == l1)
  87. ans[q] = mid[n];
  88. else {
  89. int at = find(rt, l1);
  90. if (at)
  91. ans[q] = mid[n] - (mid[dfn_r[at]] - mid[dfn_l[at] - 1]);
  92. else
  93. ans[q] = mid[dfn_r[l1]] - mid[dfn_l[l1] - 1];
  94. }
  95. } else {
  96. int at = find(rt, l), at1 = find(rt, l1);
  97. if (!at)
  98. swap(at, at1), swap(l, l1);
  99. td = 1;
  100. if (at && !at1)
  101. ans[q] = mid[dfn_r[l1]] - mid[dfn_l[l1] - 1], td = -1, l = at;
  102. else if (at1)
  103. ans[q] = mid[n] - (mid[dfn_r[at]] - mid[dfn_l[at] - 1]) -
  104. (mid[dfn_r[at1]] - mid[dfn_l[at1] - 1]),
  105. l = at, l1 = at1;
  106. r = dfn_r[l], l = dfn_l[l];
  107. r1 = dfn_r[l1], l1 = dfn_l[l1];
  108. an[r / K].push_back({ r, r1, q * td });
  109. if (l > 1) {
  110. an[min(r1, l - 1) / K].push_back({ min(r1, (l - 1)), max(r1, (l - 1)), -q * td });
  111. if (l1 > 1)
  112. an[min(l - 1, l1 - 1) / K].push_back(
  113. { min(l - 1, l1 - 1), max(l - 1, l1 - 1), q * td });
  114. }
  115. if (l1 > 1)
  116. an[min(r, l1 - 1) / K].push_back({ min(r, l1 - 1), max(r, l1 - 1), -q * td });
  117. }
  118. }
  119. }
  120. l = 0, r = 0;
  121. rep(q, 0, n / K) {
  122. if (q & 1)
  123. sort(an[q].begin(), an[q].end(), cmp);
  124. else
  125. sort(an[q].begin(), an[q].end());
  126. rep(w, 0, (int)an[q].size() - 1) {
  127. l1 = an[q][w].l, r1 = an[q][w].r;
  128. while (l > l1) mid_ans -= cnt1[val[l]], --cnt[val[l--]];
  129. while (r < r1) mid_ans += cnt[val[++r]], ++cnt1[val[r]];
  130. while (l < l1) mid_ans += cnt1[val[++l]], ++cnt[val[l]];
  131. while (r > r1) mid_ans -= cnt[val[r]], --cnt1[val[r--]];
  132. an[q][w].id < 0 ? ans[-an[q][w].id] -= mid_ans : ans[an[q][w].id] += mid_ans;
  133. }
  134. }
  135. rep(q, 1, m) if (mark[q]) printf("%lld\n", ans[q]);
  136. return 0;
  137. }

「YNOI2016」自己的发明的更多相关文章

  1. loj #6201. 「YNOI2016」掉进兔子洞

    #6201. 「YNOI2016」掉进兔子洞 您正在打galgame,然后突然发现您今天太颓了,于是想写个数据结构题练练手: 给出一个长为 nnn 的序列 aaa. 有 mmm 个询问,每次询问三个区 ...

  2. loj #2037. 「SHOI2015」脑洞治疗仪

    #2037. 「SHOI2015」脑洞治疗仪   题目描述 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见 ...

  3. LibreOJ #2036. 「SHOI2015」自动刷题机

    #2036. 「SHOI2015」自动刷题机 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 题目描述 曾经发明了信号增幅仪的发明家 SHTSC 又公开 ...

  4. 每个程序员都可以「懂」一点 Linux

    提到 Linux,作为程序员来说一定都不陌生.但如果说到「懂」Linux,可能就没有那么多人有把握了.到底用 Linux 离懂 Linux 有多远?如果决定学习 Linux,应该怎么开始?要学到什么程 ...

  5. 「MoreThanJava」计算机发展史—从织布机到IBM

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  6. 「MoreThanJava」一文了解二进制和CPU工作原理

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  7. 「MoreThanJava」机器指令到汇编再到高级编程语言

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  8. 「MoreThanJava」Day2:变量、数据类型和运算符

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  9. 「MoreThanJava」Day 4:面向对象基础

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

随机推荐

  1. PLSQL到期处理

    一.输入指令"regedit"打开注册表 二.指令输入完毕后,按回车键,会进入这个界面. 三.注册表里按HKEY_CURRENT_USER\Software\Allround Au ...

  2. 第三十三个知识点:Bellcore攻击是如何攻击使用CRT的RSA的?

    第三十三个知识点:Bellcore攻击是如何攻击使用CRT的RSA的? 注意:这篇博客是由follow论密码计算中消除错误的重要性(On the importance of Eliminating E ...

  3. 计算机系统2->从芯片说起 | 芯片怎样诞生

    这部分数字逻辑课上老师在讲CMOS部分时有讲过,当时在课堂上放了一个全英的视频,没怎么看懂,现在在研究计算机系统,自底层说起,也得从这讲起. 主要参考: <嵌入式C语言自我素养> b站相关 ...

  4. 使用.NET 6开发TodoList应用(13)——实现查询分页

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 查询中有个非常常见的需求就是后端分页,实现的方式也不算复杂,所以我们本文仅仅演示一个后端查询分页的例子. 目标 实现分页查询返 ...

  5. 【jvm】06-new一个对象到底占了多少内存?

    [jvm]06-new一个对象到底占了多少内存? 欢迎关注b站账号/公众号[六边形战士夏宁],一个要把各项指标拉满的男人.该文章已在github目录收录. 屏幕前的大帅比和大漂亮如果有帮助到你的话请顺 ...

  6. Java基础周测一、二(50题)

    一.单选题 (共50题,250分) 1.下列选项不可作为Java语言变量名的是(    ). A. a1 B. $1 C. _1 D. 21 正确答案: D 2.有一段Java应用程序,它的类名是a1 ...

  7. 编写Java程序,实现客户端向服务端上传文件的功能

    查看本章节 查看作业目录 需求说明: 实现客户端向服务端上传文件的功能 当启动服务端后,运行客户端程序,系统提示客户在客户端输入上传文件的完整路径.当客户在客户端输入完成后,服务端实现文件上传 实现思 ...

  8. Selenium_使用execute_script执行JavaScript(11)

    selenium的包含的方法已能完全满足UI自动化,但是有些时候又不得不用到执行JS的情况,比如在一个富文本框中输入1W个字,使用send_keys方法将经历漫长的输入过程,如果换成使用JS的inne ...

  9. python 单下划线与双下划线的区别

    来自为知笔记(Wiz)

  10. Nginx 加载conf.d (内文件***.conf)

    include /usr/local/nginx/conf/conf.d/*.conf;