「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序,若将子树中某点跳到该点的某个儿子,可以在该点直接二分一下。

只快了一点...

#include <bits/stdc++.h>
#define rep(q, a, b) for (int q = a, q##_end_ = b; q <= q##_end_; ++q)
#define dep(q, a, b) for (int q = a, q##_end_ = b; q >= q##_end_; --q)
#define mem(a, b) memset(a, b, sizeof a)
#define debug(a) cerr << #a << ' ' << a << "___" << endl
using namespace std;
bool cur1;
char buf[10000000], *p1 = buf, *p2 = buf;
#define Getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 10000000, stdin), p1 == p2) ? EOF : *p1++
void in(int &r) {
static char c;
r = 0;
while (c = Getchar(), c < 48)
;
do
r = (r << 1) + (r << 3) + (c ^ 48);
while (c = Getchar(), c > 47);
} const int mn = 100005;
const int mm = 500005;
int K, n, m, vl[mn], val[mn];
int head[mn], ne[mn << 1], to[mn << 1], cnt2;
#define link(a, b) link_edge(a, b), link_edge(b, a)
#define link_edge(a, b) to[++cnt2] = b, ne[cnt2] = head[a], head[a] = cnt2
#define travel(x) for (int q(head[x]); q; q = ne[q])
int ind, dfn_l[mn], dfn_r[mn];
vector<int> son[mn];
int mp[mn];
void dfs(int f, int x) {
++ind, mp[ind]=x,val[ind] = vl[x], dfn_l[x] = ind;
travel(x) if (to[q] != f) dfs(x, to[q]),son[x].push_back(dfn_l[to[q]]);
dfn_r[x] = ind;
}
int get_high(int x, int v) {
int l=0,r=(int)son[x].size()-1,ans=0;
while(l<=r){
int mid=l+r>>1;
if(son[x][mid]>v)r=mid-1;
else l=mid+1,ans=mid;
}
return mp[son[x][ans]];
}
long long ans[mm];
struct node {
int l, r, id;
inline bool operator<(const node &A) const { return r < A.r; }
};
inline bool cmp(node a, node b) { return a.r > b.r; }
vector<node> an[800];
int cnt[mn], cnt1[mn];
bool mark[mm];
long long mid_ans, mid[mn];
void init() {
dfs(0, 1); sort(mid + 1, mid + n + 1);
rep(q, 1, n) val[q] = lower_bound(mid + 1, mid + n + 1, val[q]) - mid; rep(q, 1, n)++ cnt[val[q]];
rep(q, 1, n) mid[q] = mid[q - 1] + cnt[val[q]];
rep(q, 1, n)-- cnt[val[q]];
}
int find(int rt, int x) {
if (dfn_l[rt] >= dfn_l[x] && dfn_l[rt] <= dfn_r[x])
return get_high(x, dfn_l[rt]);
return 0;
}
bool cur2;
int main() {
// cerr<<(&cur2-&cur1)/1024.0/1024<<endl;
int td, l, r, l1, r1;
in(n), in(m);
rep(q, 1, n) in(vl[q]), mid[q] = vl[q];
rep(q, 2, n) in(l), in(r), link(l, r);
init();
K = n / sqrt(m)*1.2 + 1;
int rt = 1;
rep(q, 1, m) {
in(td);
if (td == 1)
in(rt);
else {
mark[q] = 1;
in(l), in(l1);
if (rt == l || rt == l1) {
if (rt == l1)
swap(l, l1);
if (rt == l1)
ans[q] = mid[n];
else {
int at = find(rt, l1);
if (at)
ans[q] = mid[n] - (mid[dfn_r[at]] - mid[dfn_l[at] - 1]);
else
ans[q] = mid[dfn_r[l1]] - mid[dfn_l[l1] - 1];
}
} else {
int at = find(rt, l), at1 = find(rt, l1);
if (!at)
swap(at, at1), swap(l, l1);
td = 1;
if (at && !at1)
ans[q] = mid[dfn_r[l1]] - mid[dfn_l[l1] - 1], td = -1, l = at;
else if (at1)
ans[q] = mid[n] - (mid[dfn_r[at]] - mid[dfn_l[at] - 1]) -
(mid[dfn_r[at1]] - mid[dfn_l[at1] - 1]),
l = at, l1 = at1;
r = dfn_r[l], l = dfn_l[l];
r1 = dfn_r[l1], l1 = dfn_l[l1];
an[r / K].push_back({ r, r1, q * td });
if (l > 1) {
an[min(r1, l - 1) / K].push_back({ min(r1, (l - 1)), max(r1, (l - 1)), -q * td });
if (l1 > 1)
an[min(l - 1, l1 - 1) / K].push_back(
{ min(l - 1, l1 - 1), max(l - 1, l1 - 1), q * td });
}
if (l1 > 1)
an[min(r, l1 - 1) / K].push_back({ min(r, l1 - 1), max(r, l1 - 1), -q * td });
}
}
}
l = 0, r = 0;
rep(q, 0, n / K) {
if (q & 1)
sort(an[q].begin(), an[q].end(), cmp);
else
sort(an[q].begin(), an[q].end());
rep(w, 0, (int)an[q].size() - 1) {
l1 = an[q][w].l, r1 = an[q][w].r;
while (l > l1) mid_ans -= cnt1[val[l]], --cnt[val[l--]];
while (r < r1) mid_ans += cnt[val[++r]], ++cnt1[val[r]];
while (l < l1) mid_ans += cnt1[val[++l]], ++cnt[val[l]];
while (r > r1) mid_ans -= cnt[val[r]], --cnt1[val[r--]];
an[q][w].id < 0 ? ans[-an[q][w].id] -= mid_ans : ans[an[q][w].id] += mid_ans;
}
}
rep(q, 1, m) if (mark[q]) printf("%lld\n", ans[q]);
return 0;
}

「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. Java编程基础

    JDK与JRE有什么区别 JDK:Java开发工具包(Java Development Kit),提供了Java的开发环境和运行环境. JRE:Java运行环境(Java Runtime Enviro ...

  2. 【python】PyQt5 QAction 添加点击事件

    def test(): #your function ui.yourQActionName.triggered.connect(lambda:test()) #添加lambda: 就不报错了

  3. 主席树(区间第k小的数)

    题目链接: https://www.luogu.org/problem/P3834 首先要离散化,然后主席树模板. 1 #include<cstdio> 2 #include<cst ...

  4. Java Record 的一些思考 - 序列化相关

    Java Record 序列化相关 Record 在设计之初,就是为了找寻一种纯表示数据的类型载体.Java 的 class 现在经过不断的迭代做功能加法,用法已经非常复杂,各种语法糖,各种多态构造器 ...

  5. JMeter_用户自定义变量

    在实际测试过程中,我们经常会碰到脚本开发时与测试执行时的服务地址不一样的情况,为了方便,我们会把访问地址参数化,当访问地址变化了,我们只需要把参数对应的值改动一下就可以了. 一.添加用户自定义变量元件 ...

  6. CentOS6.4安装Zookeeper-3.4.12图解教程

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6595380916590215683/ 安装工具 VMware_workstation_full_12.5.2 Ce ...

  7. layui父表单获取子表单的值完成修改操作

    最近在做项目时,学着用layui开发后台管理系统. 但在做编辑表单时遇到了一个坑. 点击编辑时会出现一个弹窗. 我们需要从父表单传值给子表单.content是传值给子表单 layer.open({ t ...

  8. 记一次异步处理导致Jetty Request对象泄漏

    最近排查一个bug,发现了一系列有意思的东西,对「自定义线程池」.「Jetty线程模型」都有了一些新的认识. 本文预计阅读时间10分钟,包括: 问题表现 常见原因筛查 根因与源码分析 最佳实践 一些小 ...

  9. 【原创】阿里三面:搞透Kafka的存储架构,看这篇就够了

    阅读本文大约需要30分钟.这篇文章干货很多,希望你可以耐心读完. 你好, 我是华仔,在这个 1024 程序员特殊的节日里,又和大家见面了. 从这篇文章开始,我将对 Kafka 专项知识进行深度剖析, ...

  10. Exception in thread “main“ java.net.ConnectException: Call From

    问题描述:#报错语句:FileSystem fs = FileSystem.get(new URI("hdfs://hadoop000:8020"),new Configurati ...