「YNOI2016」自己的发明
「YNOI2016」自己的发明
不换根
基本的莫队吧...
子树直接转到dfs序上。
其余部分可以见 「SNOI2017」一个简单的询问。
换根
根root,查询x,分3种:
- root不在x子树内,按照原来dfs序区间即可
- root在x子树内且root!=x,那么就是整个序列除掉H(root的祖先,且为x儿子)对应的dfs序区间
- 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」自己的发明的更多相关文章
- loj #6201. 「YNOI2016」掉进兔子洞
#6201. 「YNOI2016」掉进兔子洞 您正在打galgame,然后突然发现您今天太颓了,于是想写个数据结构题练练手: 给出一个长为 nnn 的序列 aaa. 有 mmm 个询问,每次询问三个区 ...
- loj #2037. 「SHOI2015」脑洞治疗仪
#2037. 「SHOI2015」脑洞治疗仪 题目描述 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见 ...
- LibreOJ #2036. 「SHOI2015」自动刷题机
#2036. 「SHOI2015」自动刷题机 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 题目描述 曾经发明了信号增幅仪的发明家 SHTSC 又公开 ...
- 每个程序员都可以「懂」一点 Linux
提到 Linux,作为程序员来说一定都不陌生.但如果说到「懂」Linux,可能就没有那么多人有把握了.到底用 Linux 离懂 Linux 有多远?如果决定学习 Linux,应该怎么开始?要学到什么程 ...
- 「MoreThanJava」计算机发展史—从织布机到IBM
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- 「MoreThanJava」一文了解二进制和CPU工作原理
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- 「MoreThanJava」机器指令到汇编再到高级编程语言
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- 「MoreThanJava」Day2:变量、数据类型和运算符
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- 「MoreThanJava」Day 4:面向对象基础
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
随机推荐
- 数据结构作业——P53算法设计题(6):设计一个算法,通过一趟遍历确定长度为n的单链表中值最大的结点
思路: 设单链表首个元素为最大值max 通过遍历元素,与最大值max作比较,将较大值附给max 输出最大值max 算法: /* *title:P53页程序设计第6题 *writer:weiyuexin ...
- 后缀数组【原理+python代码】
后缀数组 参考:https://blog.csdn.net/a1035719430/article/details/80217267 https://blog.csdn.net/YxuanwKeith ...
- 昆泰CH7511B方案|EDP转LVDS资料|CS5211pin to pin 替代CH7511B电路设计
Chrontel的CH7511B是一种低成本.低功耗的半导体器件,它将嵌入式DisplayPort信号转换为LVDS(低压差分信号).这款创新的DisplayPort接收机带有集成LVDS发射机,专为 ...
- ProtoBuf3语法指南(Protocol Buffers)_下
0.说明 ProtoBuf3语法指南, 又称为proto3, 是谷歌的Protocol Buffers第3个版本. 本文基于官方英文版本翻译, 加上了自己的理解少量修改, 一共分为上下两部分. 1.A ...
- Shell自动上传下载文件到SFTP服务器
1.说明 本文提供一个Shell脚本, 可以自动连接到SFTP服务器, 然后上传或者下载指定的文件, 进而可以使用Linux的corntab命令, 定时执行脚本上传下载文件, 实现文件的同步或者备份功 ...
- Xstart远程连接Linux图形用户界面
目标: 在自己的Windows桌面打开Linux的firefox浏览器 工具: Windows: Xmanager的Xstart工具 Linux: xterm,firefox 说明: 使用Xstart ...
- PDF的信息提取的问题
PDF对企业应用来说是刚需. 然而PDF显然不是一种对机器友好的格式,它只是对人类友好,就是说方便阅读打印,但让程序去提取其中的内容却很难.下面简单说说为什么是这样. 以前还读书的时候(20+ ...
- Docker_容器(container)使用(4)
参数说明 -i: 交互式操作. -t: 终端. -d: 指定容器运行模式. --name:指定容器的NAMES字段名称,不指定则随机生成名称 --restart:容器启动策略.默认为no,常用为alw ...
- js 模块化 -- export 时 一个默认和多个默认的写法
js文件 只有一个 food 类,一般写 export {food} 或者 export {food as default} 那么如果有多个呢? 这样 export {food, food2} 或者 ...
- Module 4 - Azure SQL
1) Migrate AdventureWorks database from SQL Server instance to Azure SQL using DMA.2) Update ...