「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 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
随机推荐
- 【系统分析】《系统分析与设计方法》 Jeffrey L.Whitten 第1部分 系统开发环境 第3章 信息系统开发
1.解释为什么对企业来说,拥有一个标准的系统开发过程很重要. 开发过程的成熟,使项目时间和费用减少,生产率和质量提高 2.如何关联系统生命周期和系统开发方法学? 系统生命周期包含系统开发阶段,其中使用 ...
- MLP-Mixer: An all-MLP Architecture for Vision
目录 概 主要内容 代码 Tolstlkhin I., Houlsby N., Kolesnikov A., Beyer L., Zhai X., Unterthiner T., Yung J., S ...
- Kronecker Products and Stack Operator
目录 定义 Stack Operator Kronecker Product 性质 Stack Operator Kronecker Product 半线性 Whitcomb L. Notes on ...
- EBGAN
目录 概 主要内容 Zhao J., Mathieu M. & LeCun Y. Energy-based generative adversarial networks. ICLR, 201 ...
- 编写Java程序_找星座朋友应用软件
一.About the Project 项目介绍 自古以来,人对于恒星的排列和形状很感兴趣,并很自然地把一些位置相近的星联系起来,组成星座.占星术亦称"占星学"."星占学 ...
- Java高级程序设计笔记 • 【第6章 设计模式】
全部章节 >>>> 本章目录 6.1 设计模式 6.1.1 设计模式概述和分类 6.1.2 单列模式介绍 6.1.3 单例模式的实现 6.1.4 实践练习 6.2 单例模式 ...
- x86-2-保护模式
x86-2-保护模式 操作系统负责计算机上的所有软件和硬件的管理,它可以百分百操作计算机的所有内容.但是,操作系统上编写的用户程序却应当有所限制,只允许用户程序访问属于自己程序的内容,不然整个生态就很 ...
- 使用sudo执行命令提示command not found
笔记: 使用源码部署nginx的时候,使用sudo nginx提示command not found,但是直接使用nginx会导致权限问题: 这种情况应该是环境变量导致的,使用 env |grep P ...
- 《剑指offer》面试题53 - II. 0~n-1中缺失的数字
问题描述 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0-n-1之内.在范围0-n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字. 示例 1: 输入: [ ...
- Cesium中级教程10 - CesiumJS and webpack
Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ webpack是打包JavaScript模块流行且强大的工具.它 ...