「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 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
随机推荐
- Django项目部署到Apache服务器上
之前写了把Django部署到XAMPP上,但是有bug,翻apache日志的时候发现会无法import _ssl,然后我就怒而直接装apache2了 配置方法大约和这篇文章差不多 安装必要的包 sud ...
- [算法笔记-题解]问题 C: 例题4-3 比较交换3个实数值,并按序输出
问题 C: 例题4-3 比较交换3个实数值,并按序输出 [命题人 : 外部导入] 时间限制 : 1.000 sec 内存限制 : 12 MB 题目描述 从键盘输入3个实数a, b, c,通过比较交换, ...
- 懂得三境界-使用dubbo时请求超过问题
引子 刚才下班回家路上,无意中听到大街上放的歌,歌词有这么一句:"毡房外又有驼铃声声响起,我知道那一定不是你".这一句我似乎听懂了歌者的魂牵梦绕和绝望,如果在十年前我大概只能感受出 ...
- 编写Java程序,在子类老虎中重写父类动物的吃食方法
返回本章节 返回作业目录 需求说明: 在子类老虎中重写父类动物的吃食方法 实现思路: 在子类老虎中重写父类动物的吃食方法的实现思路如下: 创建各种动物的父类Animal类,在该类中定义eat()方法. ...
- CAD快速入门--绝望
从入门到放弃 咱是革命一块砖,哪里需要哪里搬.(需求来自领导,让我一个敲代码的画CAD图纸,可以想象我在一个什么样的公司,在为什么样的老板赚钱,不多说了下面开始学习). CAD绘图功能优化与基本操作 ...
- C# 设置或验证 PDF中的文本域格式
概述 PDF中的文本域可以通过设置不同格式,用于显示数字.货币.日期.时间.邮政编码.电话号码和社保号等等.Adobe Acrobat提供了许多固定的JavaScripts用来设置和验证文本域的格式, ...
- Unity3D开发入门教程(二)—— Lua入门
五邑隐侠,本名关健昌,12年游戏生涯. 本教程以 Unity 3D + VS Code + C# + tolua 为例. 如果你还没有编程基础,建议你先学习一些编程基础.本文不是完全菜鸟教程,主要针对 ...
- win10中查看开关机时间及查看admin的RID的方法
原文链接: https://www.toutiao.com/i6772133439593251339/ 打开系统的注册表 键盘输入win+r组合键出现运行窗口命令 输入regedit 按回车键,进入注 ...
- Maven自定义jar包名
一.默认命名 <finalName>${project.artifactId}-${project.version}</finalName> 二.自定义包名 <build ...
- jmu-ds-舞伴问题
假设在周末舞会上,男士和女士们分别进入舞厅,各自排成一队.跳舞开始,依次从男队和女队队头各出一人配成舞伴,若两队初始人数不同,则较长那一队未配对者等待下一轮舞曲.现要求写一算法模拟上述舞伴配对问题. ...