题面

给定一棵树,有点权

每次询问给出一些点对,求这些点对之间的路径的并集上不同权值的个数,以及这些权值的$mex$

思路

先考虑只有一对点对,只询问不同权值个数的问题:树上莫队模板题

然后加个$mex$:还是可以树上莫队

然后加入多组点对:这下不能莫队了

我们考虑另一种和莫队相似的算法:分块,在树上就是树分块

我们发现树分块要处理只有不同权值的问题的话,配合$bitset$食用会很好

预处理每个块顶到它的直系父亲块顶这条路径上的bitset

对于一个点对$(l,r)$,分开处理两条只有上下的链:$(l,lca)$和$(r,lca)$

链中间的部分跳块,两边的部分暴力跳

然后我们发现树分块+bitset可以处理多组点对的问题,因为bitset可以按位或起来

然后我们又发现bitset有一个叫find_first的东西,于是mex也解决了

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<bitset>
#include<queue>
#define last DEEP_DARK_FANTASY
#define ll long long
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,m,op;
int first[100010],cnte=-1;
struct edge{
int to,next;
}a[200010];int w[100010];
inline void add(int u,int v){
a[++cnte]=(edge){v,first[u]};first[u]=cnte;
a[++cnte]=(edge){u,first[v]};first[v]=cnte;
}
int dep[100010],siz[100010],son[100010],top[100010],fa[100010],dfn[100010],clk;
void dfs1(int u,int f){//树剖lca
int i,v;
fa[u]=f;
dep[u]=dep[f]+1;
siz[u]=1;son[u]=0;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(v==f) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(int u,int t){
int i,v;
top[u]=t;dfn[u]=++clk;
if(son[u]) dfs2(son[u],t);
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(v==son[u]||v==fa[u]) continue;
dfs2(v,v);
}
}
int lca(int l,int r){
while(top[l]!=top[r]){
if(dep[top[l]]>dep[top[r]]) swap(l,r);
r=fa[top[r]];
}
if(dep[l]>dep[r]) swap(l,r);
return l;
}
bitset<100010>tmp,st[150][150];
int id[100010],vis[100010],cntd,pos[100010],belong[100010],pre[100010],blk;
void getst(int u){
if(!u||vis[u]) return;
vis[u]=1;
id[u]=++cntd;
tmp.reset();
while(u){
tmp[w[u]]=1;
if(pre[u]==u){
st[cntd][belong[u]]=tmp;
}
u=fa[u];
}
}
void dfs(int u,int f){
int i,v;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(v==f) continue;
if(belong[u]==belong[v]) pre[v]=pre[u];
else pre[v]=v;
dfs(v,u);
}
if(pre[u]==u) getst(fa[u]);
}
void build(){//树分块
int i,u,v;
for(i=1;i<=n;i++) pos[i]=i;
random_shuffle(pos+1,pos+n+1);//神秘的树分块技巧:随机块顶......
blk=min(n,150);
queue<int>q;
for(i=1;i<=blk;i++){
belong[pos[i]]=i;
q.push(pos[i]);
}
while(!q.empty()){
int u=q.front();q.pop();
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(belong[v]) continue;
q.push(v);belong[v]=belong[u];
}
}
pre[1]=1;
dfs(1,0);
}
inline void jump(int u,int v){
if(dep[u]<dep[v]) return;
while(u!=v){
tmp[w[u]]=1;
u=fa[u];
}
tmp[w[u]]=1;
}
inline void solve(int u,int t){
if(belong[u]==belong[t]){
jump(u,t);
return;
}
jump(u,pre[u]);
int v=fa[pre[u]],x=0;
while(dep[pre[v]]>=dep[t]){
x=belong[v];
v=fa[pre[v]];
}
if(x) tmp|=st[id[fa[pre[u]]]][x];
jump(v,t);
}
int main(){
memset(first,-1,sizeof(first));
n=read();m=read();op=read();
int i,t3,t1,t2,j,last=0;
for(i=1;i<=n;i++) w[i]=read();
for(i=1;i<n;i++){
t1=read();t2=read();
add(t1,t2);
}
dfs1(1,0);
dfs2(1,1);
build();
while(m--){
j=read();tmp.reset();
for(i=1;i<=j;i++){
t1=read();t2=read();
t1^=(last*op);
t2^=(last*op);
t3=lca(t1,t2);
solve(t1,t3);
solve(t2,t3);
}
t1=tmp.count();
tmp.flip();
t2=tmp._Find_first();
printf("%d %d\n",t1,t2);
last=t1+t2;
}
}

种树 by yoyoball [树分块+bitset]的更多相关文章

  1. 洛谷 P6177 - Count on a tree II/【模板】树分块(树分块)

    洛谷题面传送门 好家伙,在做这道题之前我甚至不知道有个东西叫树分块 树分块,说白了就是像对序列分块一样设一个阈值 \(B\),然后在树上随机撒 \(\dfrac{n}{B}\) 个关键点,满足任意一个 ...

  2. 【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)

    2016-05-09 UPD:学习了新的DFS序列分块,然后发现这个东西是战术核导弹?反正比下面的树分块不知道要快到哪里去了 #include<cmath> #include<cst ...

  3. 2015北京网络赛 J Clarke and puzzle 求五维偏序 分块+bitset

    Clarke and puzzle Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://hihocoder.com/contest/acmicpc20 ...

  4. [BZOJ 1086] [SCOI2005] 王室联邦 【树分块】

    题目链接:BZOJ - 1086 题目分析 这道题要求给树分块,使得每一块的大小在 [B, 3B] 之间,并且可以通过一个块外的节点(块根)使得整个块联通. 那么我们使用一种 DFS,维护一个栈,DF ...

  5. hihocoder1236(北京网络赛J):scores 分块+bitset

    北京网络赛的题- -.当时没思路,听大神们说是分块+bitset,想了一下发现确实可做,就试了一下,T了好多次终于过了 题意: 初始有n个人,每个人有五种能力值,现在有q个查询,每次查询给五个数代表查 ...

  6. 洛谷.2590.[ZJOI2008]树的统计(树分块)

    题目链接 Update:这种分块写法...可以被卡掉啊... 好像没有靠谱的树分块写法... /* 对树上节点进行分块,每个点记录dep,fa,val,Max,Sum,Max,Sum表示当前点在该块内 ...

  7. BZOJ.3720.Gty的妹子树(树分块)

    题目链接 洛谷上惨遭爆零是为什么.. 另外这个树分块算法是假的. /* 插入删除只涉及一个数,故每次可以枚举一遍,而不是重构完后sort */ #include<cmath> #inclu ...

  8. hdu 4366 Successor - CDQ分治 - 线段树 - 树分块

    Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty an ...

  9. 【bzoj2741】[FOTILE模拟赛]L 可持久化Trie树+分块

    题目描述 FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor A ...

随机推荐

  1. Element-ui树形控件el-tree获取父级节点的id

    Element-ui官网给的方法 getCheckedKeys() { console.log(this.$refs.tree.getCheckedKeys()); }, 这种只有在所有子级都被选中的 ...

  2. 【vlan之四种方式链路认证组网]

    ---恢复内容开始--- 根据项目需求,搭建好如下拓扑图: 在[sysname]下配置给予协议的vlan vlan 1#vlan 10 protocol-vlan 0 ipv4#vlan 20 pro ...

  3. Java : JPA相关以及常用注解

    SpringDataJPA自定义的查询方法 定义规范       And 并且 Or 或     Is,Equals 等于 Between 两者之间 LessThan 小于 LessThanEqual ...

  4. 如何保证HashMap线程安全

    可使用Java 1.5推荐的java.util.concurrent包ConcurrentHashMap来实现,内部不再使用类似HashTable的synchronized同步锁,而是使用Reentr ...

  5. C# static const和readonly区别

    Const 定义的是静态常在对象初始化的时候赋值.以后不能改变它的值.属于编译时常量. Static 定义的是静态变量.可以再外部改变它的值.. Readonly 是只读变量.属于运行时变量.可以在类 ...

  6. 【TRICK】[0,n)中所有大小为k的子集的方法

    << k) - ; <<n)) { int x = comb & -comb, y = comb + x; comb = (((comb & ~y)/x)> ...

  7. java冒泡算法

    public static void maopao() { int temp; int[] values = {2, 34, 0, 245}; for (int i = 0; i < value ...

  8. Linux - 信息收集

    1. #!,代表加载器(解释器)的路径,如: #!/bin/bash echo "Hello Boy!" 上面的意思是说,把下面的字符(#!/bin/bash以下的所有字符)统统传 ...

  9. 如何在Centos7下升级Apache至最新版本

    Apache是使用最广泛的应用部署软件.并且它也是所有服务器的必要组成部分.安装最新版本的apache意味着拥有更多最新的功能和修复了已知的BUG. 介绍 在这篇教程里面,我将会介绍在Centos7下 ...

  10. Java的HashMap和HashTable

    Java的HashMap和HashTable 1. HashMap 1)  hashmap的数据结构 Hashmap是一个数组和链表的结合体(在数据结构称“链表散列“),如下图示: 当我们往hashm ...