题目链接:洛谷

又来做Ynoi里面的水题了。。。

首先换根的话是一个套路,首先以1为根dfs,然后画一画就知道以rt为根,x的子树是什么了。可以拆分为2个dfs连续段。

然后如果要计算\([l_1,r_1]\)与\([l_2,r_2]\)的答案,那么就是那么做一个二维差分就可以改成\([1,r_1]\)与\([1,r_2]\)的答案了。用\((r_1,r_2)\)做莫队就可以过了。

注意有一点,要去除那些不必要的询问,即\(r_1=0\)或者\(r_2=0\),这样就可以去掉大量的询问,不然会T掉3个点。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 100003;
int n, m, tot, len, blo, rt, head[N], to[N << 1], nxt[N << 1], a[N], b[N], dfn[N], pre[N], dep[N], fa[N], siz[N], wson[N], top[N], tim;
LL ans[N * 5];
inline void add(int a, int b){
static int cnt = 0;
to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
}
inline void dfs1(int x){
siz[x] = 1;
for(Rint i = head[x];i;i = nxt[i])
if(to[i] != fa[x]){
dep[to[i]] = dep[x] + 1; fa[to[i]] = x;
dfs1(to[i]);
siz[x] += siz[to[i]];
if(siz[to[i]] > siz[wson[x]]) wson[x] = to[i];
}
}
inline void dfs2(int x, int tp){
top[x] = tp; dfn[x] = ++ tim; pre[tim] = x;
if(wson[x]){
dfs2(wson[x], tp);
for(Rint i = head[x];i;i = nxt[i])
if(to[i] != fa[x] && to[i] != wson[x])
dfs2(to[i], to[i]);
}
}
inline int calc(int x, int y){
while(dep[x] > dep[y]){
if(dep[top[x]] <= dep[y]) return wson[y];
if(fa[top[x]] == y) return top[x];
x = fa[top[x]];
}
return x;
}
struct Query {
int l, r, id;
bool flag;
inline bool operator < (const Query &o) const {
if(l / blo != o.l / blo) return l / blo < o.l / blo;
if((l / blo) & 1) return r > o.r;
return r < o.r;
}
} que[N * 80];
inline void add(int l1, int r1, int l2, int r2, int id){
if(r1 && r2){que[++ tot].l = r1; que[tot].r = r2; que[tot].id = id; que[tot].flag = false;}
if(l1 > 1 && r2){que[++ tot].l = l1 - 1; que[tot].r = r2; que[tot].id = id; que[tot].flag = true;}
if(r1 && l2 > 1){que[++ tot].l = r1; que[tot].r = l2 - 1; que[tot].id = id; que[tot].flag = true;}
if(l1 > 1 && l2 > 1){que[++ tot].l = l1 - 1; que[tot].r = l2 - 1; que[tot].id = id; que[tot].flag = false;}
}
int ql = 0, qr = 0, cnt1[N], cnt2[N];
LL qans = 0;
inline void add1(int x){++ cnt1[x]; qans += cnt2[x];}
inline void del1(int x){-- cnt1[x]; qans -= cnt2[x];}
inline void add2(int x){++ cnt2[x]; qans += cnt1[x];}
inline void del2(int x){-- cnt2[x]; qans -= cnt1[x];}
int main(){
scanf("%d%d", &n, &m); blo = sqrt(n);
for(Rint i = 1;i <= n;i ++) scanf("%d", a + i), b[i] = a[i];
sort(b + 1, b + n + 1);
len = unique(b + 1, b + n + 1) - b - 1;
for(Rint i = 1;i <= n;i ++) a[i] = lower_bound(b + 1, b + len + 1, a[i]) - b;
for(Rint i = 1;i < n;i ++){
int a, b; scanf("%d%d", &a, &b); add(a, b); add(b, a);
}
dfs1(1); dfs2(1, 1); rt = 1;
int pos = 0;
while(m --){
int opt, x, y;
scanf("%d", &opt);
if(opt == 1) scanf("%d", &rt);
else {
scanf("%d%d", &x, &y); ++ pos;
int l1[2], r1[2], l2[2], r2[2], cnt1 = 0, cnt2 = 0;
if(rt == x) l1[0] = 1, r1[0] = n, cnt1 = 1;
else if(dfn[rt] > dfn[x] && dfn[rt] < dfn[x] + siz[x]){
int tmp = calc(rt, x);
l1[0] = 1; r1[0] = dfn[tmp] - 1; l1[1] = dfn[tmp] + siz[tmp]; r1[1] = n; cnt1 = 2;
} else l1[0] = dfn[x], r1[0] = dfn[x] + siz[x] - 1, cnt1 = 1;
if(rt == y) l2[0] = 1, r2[0] = n, cnt2 = 1;
else if(dfn[rt] > dfn[y] && dfn[rt] < dfn[y] + siz[y]){
int tmp = calc(rt, y);
l2[0] = 1; r2[0] = dfn[tmp] - 1; l2[1] = dfn[tmp] + siz[tmp]; r2[1] = n; cnt2 = 2;
} else l2[0] = dfn[y], r2[0] = dfn[y] + siz[y] - 1, cnt2 = 1;
for(Rint i = 0;i < cnt1;i ++)
for(Rint j = 0;j < cnt2;j ++)
add(l1[i], r1[i], l2[j], r2[j], pos);
}
}
for(Rint i = 1;i <= tot;i ++)
if(que[i].l > que[i].r) swap(que[i].l, que[i].r);
sort(que + 1, que + tot + 1);
for(Rint i = 1;i <= tot;i ++){
while(ql < que[i].l) add1(a[pre[++ ql]]);
while(ql > que[i].l) del1(a[pre[ql --]]);
while(qr < que[i].r) add2(a[pre[++ qr]]);
while(qr > que[i].r) del2(a[pre[qr --]]);
if(que[i].flag) ans[que[i].id] -= qans;
else ans[que[i].id] += qans;
}
for(Rint i = 1;i <= pos;i ++) printf("%lld\n", ans[i]);
}

Luogu4689 [Ynoi2016]这是我自己的发明 【莫队】的更多相关文章

  1. [Ynoi2016]这是我自己的发明 莫队

    传送门:here 很棒的莫队题啊..... 题意: 有一棵$ n$个点的树,树上每个点有点权,有$ m$次询问: 操作1:给定两个点$ x,y$,求二元组$ (a,b)$的数量,要求$ a$在$ x$ ...

  2. 洛谷P4689 [Ynoi2016]这是我自己的发明 [莫队]

    传送门 ynoi中比较良心不卡常的题. 思路 没有换根操作时显然可以变成dfs序莫队随便搞. 换根操作时一个子树可以变成两段区间的并集,也随便搞搞就好了. 这题完全不卡常,随便过. 代码 #inclu ...

  3. bzoj4940 [Ynoi2016]这是我自己的发明 莫队+dfs序

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4940 题解 对于换根操作,处理方法就很套路了. 首先先假定以 \(1\) 为根做一遍 dfs, ...

  4. 【洛谷 P4688】 [Ynoi2016]掉进兔子洞(bitset,莫队)

    题目链接 第一道Ynoi 显然每次询问的答案为三个区间的长度和减去公共数字个数*3. 如果是公共数字种数的话就能用莫队+bitset存每个区间的状态,然后3个区间按位与就行了. 但现在是个数,bits ...

  5. luogu P4688 [Ynoi2016]掉进兔子洞 bitset 莫队

    题目链接 luogu P4688 [Ynoi2016]掉进兔子洞 题解 莫队维护bitset区间交个数 代码 // luogu-judger-enable-o2 #include<cmath&g ...

  6. YNOI2016:掉进兔子洞 (莫队+bitset)

    YNOI2016:掉进兔子洞 题意简述: 有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立. 注意这里删掉指的是一个一个删,不是把等于这 ...

  7. [Luogu 4688] [Ynoi2016]掉进兔子洞 (莫队+bitset)

    [Luogu 4688] [Ynoi2016]掉进兔子洞 (莫队+bitset) 题面 一个长为 n 的序列 a.有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间 ...

  8. 洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)

    洛谷题目传送门 具体思路看别的题解吧.这里只提两个可能对常数和代码长度有优化的处理方法. I 把一个询问拆成\(9\)个甚至\(16\)个莫队询问实在是有点珂怕. 发现询问的一边要么是一个区间,要么是 ...

  9. bzoj4940: [Ynoi2016]这是我自己的发明

    用dfs序把询问表示成询问dfs序的两个区间中的信息 拆成至多9个询问(询问dfs序的两个前缀),对这些询问用莫队处理,时间复杂度$O(n\sqrt{m})$ #include<bits/std ...

随机推荐

  1. react 提示消息队列 (支持动态添加,删除,多实例化)

    import React from 'react' import PropTypes from 'prop-types' import AnimationOperateFeedbackInfo fro ...

  2. redis-desktop-manager 0.9.3 安装(最后一个免费版本)

    使用Chocolatey(Windows包管理工具)安装 官方安装说明 https://chocolatey.org/install 安装redis-desktop-manager 官方安装说明 ht ...

  3. zabbix4.2的yum+mariadb方式部署安装

    本文依据官方文档操作(英文4.2):https://www.zabbix.com/documentation/4.2/manual/installation/install_from_packages ...

  4. TR-TR模块资料汇总

    转载: TR模块培训 https://www.docin.com/p-1704805923.html 现金管理(Cash Management)和预算控制(Cash Budget Management ...

  5. python OpenCV使用

    关于OpenCV简介  OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows.Android和Mac OS操作系统上.它轻量级而且高效——由一系列 C ...

  6. Java原子操作类汇总(2)

    当程序更新一个变量时,如果是多线程同时更新这个变量,可能得到的结果与期望值不同.比如:有一个变量i,A线程执行i+1,B线程也执行i+1,经过两个线程的操作后,变量i的值可能不是期望的3,而是2.这是 ...

  7. Android笔记(三十四) Android中线程之间的通信(六)Handle中的post()方法详解

    我们之前都是使用sendMessage()方法来发送消息,使用handleMessage来处理消息的,今天我们来看另外一种方法,先看代码: package cn.lixyz.handlertest; ...

  8. /etc/apt/sources.list 和 /etc/apt/sources.list.d

    转自:大数据云技术基础之Linux源:/etc/apt/sources.list文件 导读 1./etc/apt/sources.list的作用是什么?2.为什么会产生 /etc/apt/source ...

  9. 安装腾讯QQ问题记录

    安装腾讯QQ的时候遇到两个错误,记录一些解决方法 1.安装文件失败,请尝试手动卸载QQ或更改安装目录,再执行安装程序,错误码:0x00008013 问题原因:卸载QQ没有完全卸载,导致文件残留. 如果 ...

  10. 用js刷剑指offer(二叉搜索树的后序遍历序列)

    题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 牛客网链接 js代码 function Verif ...