【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法
题目描述
输入
输出
对于每个询问,输出一个数表示答案。
样例输入
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序+树上倍增+莫队算法的更多相关文章
- bzoj4940: [Ynoi2016]这是我自己的发明
用dfs序把询问表示成询问dfs序的两个区间中的信息 拆成至多9个询问(询问dfs序的两个前缀),对这些询问用莫队处理,时间复杂度$O(n\sqrt{m})$ #include<bits/std ...
- bzoj4940 [Ynoi2016]这是我自己的发明 莫队+dfs序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4940 题解 对于换根操作,处理方法就很套路了. 首先先假定以 \(1\) 为根做一遍 dfs, ...
- YNOI2016:掉进兔子洞 (莫队+bitset)
YNOI2016:掉进兔子洞 题意简述: 有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立. 注意这里删掉指的是一个一个删,不是把等于这 ...
- 【bzoj4940】这是我自己的发明
Portal --> bzoj4940 Solution (原题这题面到底是..怎么回事啊深深的套路qwq) 感觉自己对根号的算法还是很..没有感觉啊== 实际上这题和bzoj5016没有任何区 ...
- luogu P4688 [Ynoi2016]掉进兔子洞 bitset 莫队
题目链接 luogu P4688 [Ynoi2016]掉进兔子洞 题解 莫队维护bitset区间交个数 代码 // luogu-judger-enable-o2 #include<cmath&g ...
- [Luogu 4688] [Ynoi2016]掉进兔子洞 (莫队+bitset)
[Luogu 4688] [Ynoi2016]掉进兔子洞 (莫队+bitset) 题面 一个长为 n 的序列 a.有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间 ...
- 洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)
洛谷题目传送门 具体思路看别的题解吧.这里只提两个可能对常数和代码长度有优化的处理方法. I 把一个询问拆成\(9\)个甚至\(16\)个莫队询问实在是有点珂怕. 发现询问的一边要么是一个区间,要么是 ...
- [Ynoi2016]这是我自己的发明 莫队
传送门:here 很棒的莫队题啊..... 题意: 有一棵$ n$个点的树,树上每个点有点权,有$ m$次询问: 操作1:给定两个点$ x,y$,求二元组$ (a,b)$的数量,要求$ a$在$ x$ ...
- 洛谷P4689 [Ynoi2016]这是我自己的发明 [莫队]
传送门 ynoi中比较良心不卡常的题. 思路 没有换根操作时显然可以变成dfs序莫队随便搞. 换根操作时一个子树可以变成两段区间的并集,也随便搞搞就好了. 这题完全不卡常,随便过. 代码 #inclu ...
随机推荐
- 前端HTML基础
1.0开发工具介绍 sublime的使用技巧链接 HTML特殊符号表 1.1 html概念 超文本标记语言(Hypertext Markup Language),属于一种描述性的标记语言(markup ...
- org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [spring/applicationContext-service.xml]: Cannot resolve refer
<!-- aop --> <aop:config> <aop:pointcut expression="execution(* com.zsn.Service. ...
- 在haoodp-2.7.3 HA的基础上安装Hbase HA
前提安装好hadoop基于QJM的高可用 node1 HMaster node2 HMaster.HRegionServer node3 HRegionServer node4 HRegionServ ...
- php集成开发环境xampp的搭建
一:运维闲谈 作为一名linux运维工程师,在确保能够有熟练的服务器的搭建和维护优化技能的前提,还需对自身解决问题方法上做出一番功夫. 如何为自己的运维工作添砖加瓦,自动化运维便变得非常重要,一方面, ...
- 用python实现【五猴分桃】问题
转载链接:https://blog.csdn.net/cy309173854/article/details/78296839 据说“五猴分桃”问题最先是由大物理学家狄拉克提出来的,这一貌似简单的问题 ...
- 15,redis基础学习
redis Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件 yum安装redis 1.yum安装 #前提得配置好阿里云yum源,epel源 #查看 ...
- [原]sencha touch之表单二(注册页面)
接着上一篇的登陆页面,来一个最简单的注册页面,几乎包含了常用的field Ext.application({ id:'itKingApp', launch:function(){ var formPa ...
- CodeForces 547E Mike and Friends AC自动机 主席树
题意: 给出\(n\)个字符串\(s_i\)和\(q\)个询问: \(l,r,k\):\(\sum\limits_{i=l}^{r}count(i, k)\),其中\(count(i,j)\)表示\( ...
- luoguP1726 上白泽慧音
P1726 上白泽慧音 题目描述 在幻想乡,上白泽慧音是以知识渊博闻名的老师.春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄.因此慧音决定换一个能够聚集最多人数的村 ...
- Toolbar中menu菜单文字颜色的修改
Toolbar菜单中menu当中我们大多数都使用图片来按钮,可是有些时候我们也会直接使用文字,文字的颜色如何修改呢. 其实很简单,我们只要修改styles.xml文件中,添加一句 <item n ...