题目描述

给一个树,n 个点,有点权,初始根是 1。
m 个操作,每次操作:
1. 将树根换为 x。
2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等,ans++,求 ans。

输入

第一行两个数表示 n,m。
第二行 n 个数,表示每个点的点权 a[i]。
之后 n - 1 行 , 每行两个数 x , y , 表示一条边
之后 m 行,每行为 1 x 或者 2 x y。
1 x,表示将根变成 x点。
2 x y,表示查询 x 点的子树与 y 点的子树。
n <= 100000 , m <= 500000 , 1 <= a[i] <= 1000000000

输出

对于每个询问,输出一个数表示答案。

样例输入

5 5
1 2 3 4 5
1 2
1 3
3 4
3 5
2 4 5
2 1 5
2 3 5
1 5
2 4 5

样例输出

0
1
1
1


题解

DFS序+树上倍增+莫队算法

如果没有换根操作的话,那么子树一定是dfs序上的一段区间。于是可以直接当成区间来做。

当有换根操作时,参考 bzoj3083遥远的国度 ,可以将子树变为dfs序上至多2段区间。当根在原子树内时可以使用树上倍增法找到对应位置。

然后的问题就转化为了 bzoj5016一个简单的询问 ,将一个询问拆成不超过9个只包含两个参数的询问,然后上莫队算法即可。

关于莫队算法的时间复杂度:实际上为每$\frac n{\sqrt m}$分一块,这样左端点块内移动次数为$O(m·\frac n{\sqrt m}=n\sqrt m)$,右端点向右移动次数为$O(\sqrt m·n=n\sqrt m)$,所以总时间复杂度为$O(n\sqrt m)$,可以通过此题。

然而出题人卡常,需要将块的大小*2并加上fread、fwrite才能勉强通过。。。

#include <cmath>
#include <cctype>
#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
int a[N] , v[N] , head[N] , to[N << 1] , next[N << 1] , cnt , root = 1 , fa[N][20] , deep[N] , Log[N] , w[N] , pos[N] , last[N] , tp , si , tot , cq;
int vx[5] , ox[5] , tx , vy[5] , oy[5] , ty , cx[N] , cy[N];
long long ans[N * 5];
struct data
{
int l , r , bl , id , opt;
data() {}
data(int L , int R , int Id , int Opt) {l = min(L , R) , r = max(L , R) , id = Id , opt = Opt;}
bool operator<(const data &a)const {return bl == a.bl ? r < a.r : l < a.l;}
}q[N * 45];
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x)
{
int i;
pos[x] = ++tp , w[tp] = a[x];
for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x][0])
fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]);
last[x] = tp;
}
inline int find(int x , int y)
{
int i;
for(i = Log[deep[y] - deep[x]] ; ~i ; i -- )
if(deep[y] - deep[x] > (1 << i))
y = fa[y][i];
return y;
}
inline char nc()
{
static char buf[100000] , *p1 , *p2;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
int ret = 0; char ch = nc();
while(!isdigit(ch)) ch = nc();
while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc();
return ret;
}
char pbuf[100000] , *pp = pbuf;
inline void push(const char ch)
{
if(pp == pbuf + 100000) fwrite(pbuf , 1 , 100000 , stdout) , pp = pbuf;
*pp ++ = ch;
}
inline void write(long long x)
{
static char sta[20];
int top = 0;
if(!x) push('0');
while(x) sta[++top] = x % 10 ^ '0' , x /= 10;
while(top) push(sta[top -- ]);
push('\n');
}
inline void flush()
{
fwrite(pbuf , 1 , pp - pbuf , stdout);
}
int main()
{
int n = read() , m = read() , i , j , k , t , x , y , z , px = 0 , py = 0;
long long now = 0;
for(i = 1 ; i <= n ; i ++ ) v[i] = a[i] = read();
sort(v + 1 , v + n + 1);
for(i = 1 ; i <= n ; i ++ ) a[i] = lower_bound(v + 1 , v + n + 1 , a[i]) - v;
for(i = 2 ; i <= n ; i ++ ) x = read() , y = read() , add(x , y) , add(y , x) , Log[i] = Log[i >> 1] + 1;
dfs(1);
for(i = 1 ; i <= m ; i ++ )
{
t = read() , x = read();
if(t == 1) root = x;
else
{
y = read() , cq ++ ;
tx = ty = 0;
if(x == root) vx[++tx] = n , ox[tx] = 1;
else if(pos[root] < pos[x] || pos[root] > last[x]) vx[++tx] = last[x] , ox[tx] = 1 , vx[++tx] = pos[x] - 1 , ox[tx] = -1;
else z = find(x , root) , vx[++tx] = n , ox[tx] = 1 , vx[++tx] = last[z] , ox[tx] = -1 , vx[++tx] = pos[z] - 1 , ox[tx] = 1;
if(y == root) vy[++ty] = n , oy[ty] = 1;
else if(pos[root] < pos[y] || pos[root] > last[y]) vy[++ty] = last[y] , oy[ty] = 1 , vy[++ty] = pos[y] - 1 , oy[ty] = -1;
else z = find(y , root) , vy[++ty] = n , oy[ty] = 1 , vy[++ty] = last[z] , oy[ty] = -1 , vy[++ty] = pos[z] - 1 , oy[ty] = 1;
for(j = 1 ; j <= tx ; j ++ )
for(k = 1 ; k <= ty ; k ++ )
if(vx[j] && vy[k])
q[++tot] = data(vx[j] , vy[k] , cq , ox[j] * oy[k]);
}
}
si = (int)(n / sqrt(tot)) * 2 + 1;
for(i = 1 ; i <= tot ; i ++ ) q[i].bl = (q[i].l - 1) / si;
sort(q + 1 , q + tot + 1);
for(i = 1 ; i <= tot ; i ++ )
{
while(px < q[i].l) px ++ , now += cy[w[px]] , cx[w[px]] ++ ;
while(py < q[i].r) py ++ , now += cx[w[py]] , cy[w[py]] ++ ;
while(px > q[i].l) cx[w[px]] -- , now -= cy[w[px]] , px -- ;
while(py > q[i].r) cy[w[py]] -- , now -= cx[w[py]] , py -- ;
ans[q[i].id] += now * q[i].opt;
}
for(i = 1 ; i <= cq ; i ++ ) write(ans[i]);
flush();
return 0;
}

【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法的更多相关文章

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

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

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

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

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

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

  4. 【bzoj4940】这是我自己的发明

    Portal --> bzoj4940 Solution (原题这题面到底是..怎么回事啊深深的套路qwq) 感觉自己对根号的算法还是很..没有感觉啊== 实际上这题和bzoj5016没有任何区 ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. java基础必备单词讲解 day six

    development development development development 开发 development developmentenvironment environment en ...

  2. oracle数据库 网页管理360浏览器登录不上

    使用谷歌浏览器可以登陆,然后在使用360之类的浏览器 就可以登录了

  3. What is JPA

    What is JPA JPA可以看做是EJB3.0的一部分,但它又不限于EJB 3.0,你可以在Web应用.甚至桌面应用中使用.JPA只是一种Java持久化标准,它意在规范ORM(对象关系映射模型) ...

  4. linux环境下安装 openOffice 并启动服务

    一.背景故事 这两天遇到一个大坑,客户要做office 文档在线预览功能,于是乎就要把office文档转换成pdf交给前端显示.      在某度找了一圈都说openOffice+jodconvert ...

  5. flask项目实战--论坛

    项目结构搭建 1:用pycharm创建flask bbs项目 2:分别创建config.py.exts.py.models.py.manage.py文件 创建一个apps包存放前台,后台,公共的模块 ...

  6. 快速排序算法Java实现

    1) 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行 示例: package ...

  7. Leetcode 337. 打家劫舍 III

    题目链接 https://leetcode.com/problems/house-robber-iii/description/ 题目描述 在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可 ...

  8. keil调试问题记录

    1.错误类型:L6218E:Underfined symbol &&&&&&&&& (referred form &&a ...

  9. Hive环境搭建及基本操作

    伪分布式 一.安装及配置Hive 1.配置HADOOP_HOME和Hive conf 目录hive-env.sh # Set HADOOP_HOME to point to a specific ha ...

  10. 流量操控之SSH隧道与端口转发

    目  录 第1章            概述... 3 1.1.         实现命令... 3 1.2.         SSH隧道类型... 3 第2章            SSH隧道... ...