正题

题目链接:https://www.luogu.com.cn/problem/P6177


题目大意

\(n\)个点的一棵树\(m\)次询问树上颜色。

强制在线

\(1\leq n\leq 4\times 10^5,1\leq m\leq 10^5,0\leq val_i<2^{31}\)


解题思路

把所有深度为\(\sqrt n\)并且下面至少有\(\sqrt n\)的深度的点标记,这样保证关键点数量不超过\(\sqrt n\)。

然后每个点到他周围关键点的距离也不会超过 \(\sqrt n\) 。

这样可以处理出关键点两两之间的颜色\(bitset\),然后每次路径找两个最近的关键点爆做就好了。

时间复杂度\(O((m+n)(\sqrt n+\frac{n}{\omega}))\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cmath>
using namespace std;
const int N=41000,T=300,M=(4e4)/T+10;
struct node{
int to,next;
}a[N<<1];
int n,m,tot,cnt,sum,fa[N],v[N],top[N],ls[N],d[N],dep[N],w[N],b[N],mark[N],dfn[N],ed[N],g[M][M];
bitset<N> f[M][M],bt;
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void dfs(int x){
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa[x])continue;
dep[y]=dep[x]+1;
fa[y]=x;dfs(y);
d[x]=max(d[x],d[y]+1);
}
if(dep[x]%T==0&&d[x]>=T)
mark[x]=++cnt;
return;
}
void dFs(int x){
if(mark[x])top[x]=x;dfn[x]=++cnt;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa[x])continue;
top[y]=top[x];dFs(y);
}
ed[x]=cnt;
return;
}
void calc(int x,int p,int fa){
if(!v[w[x]])bt[w[x]]=1,sum++;v[w[x]]++;
if(mark[x])f[p][mark[x]]=bt,g[p][mark[x]]=sum;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
calc(y,p,x);
}
v[w[x]]--;if(!v[w[x]])bt[w[x]]=0,sum--;
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]),b[i]=w[i];
sort(b+1,b+1+n);
int L=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
w[i]=lower_bound(b+1,b+1+L,w[i])-b;
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addl(x,y);addl(y,x);
}
dfs(1);cnt=0;dFs(1);
for(int i=1;i<=n;i++)
if(mark[i])calc(i,mark[i],i);
int last=0;
while(m--){
int x,y;
scanf("%d%d",&x,&y);
x^=last;
if(top[x]==top[y]){
int xx=x,yy=y,ans=0;
while(x!=y){
if(dep[x]<dep[y])swap(x,y);
if(!v[w[x]])ans++,v[w[x]]=1;
x=fa[x];
}
if(!v[w[x]])ans++,v[w[x]]=1;
printf("%d\n",ans);last=ans;
x=xx;y=yy;
while(x!=y){
if(dep[x]<dep[y])swap(x,y);
v[w[x]]=0;x=fa[x];
}
v[w[x]]=0;
}
else{
if(dfn[x]>=dfn[y]&&dfn[x]<=ed[y])swap(x,y);
if(dfn[y]>=dfn[x]&&dfn[y]<=ed[x]){
int z=top[y];
while(top[fa[z]]!=top[x])
z=top[fa[z]];
bt=f[mark[z]][mark[top[y]]];
int ans=g[mark[z]][mark[top[y]]];
while(y!=top[y]){
if(!bt[w[y]])ans++,bt[w[y]]=1;
y=fa[y];
}
while(z!=x){
if(!bt[w[z]])ans++,bt[w[z]]=1;
z=fa[z];
}
if(!bt[w[z]])ans++,bt[w[z]]=1;
printf("%d\n",ans);last=ans;
}
else{
bt=f[mark[top[x]]][mark[top[y]]];
int ans=g[mark[top[x]]][mark[top[y]]];
while(x!=top[x]){
if(!bt[w[x]])ans++,bt[w[x]]=1;
x=fa[x];
}
while(y!=top[y]){
if(!bt[w[y]])ans++,bt[w[y]]=1;
y=fa[y];
}
printf("%d\n",ans);last=ans;
}
}
}
return 0;
}

P6177-Count on a tree II/[模板]树分块的更多相关文章

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

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

  2. 【BZOJ2589】 Spoj 10707 Count on a tree II

    BZOJ2589 Spoj 10707 Count on a tree II Solution 吐槽:这道题目简直...丧心病狂 如果没有强制在线不就是树上莫队入门题? 如果加了强制在线怎么做? 考虑 ...

  3. 【BZOJ2589】[SPOJ10707]Count on a tree II

    [BZOJ2589][SPOJ10707]Count on a tree II 题面 bzoj 题解 这题如果不强制在线就是一个很\(sb\)的莫队了,但是它强制在线啊\(qaq\) 所以我们就用到了 ...

  4. SPOJ COT2 - Count on a tree II(LCA+离散化+树上莫队)

    COT2 - Count on a tree II #tree You are given a tree with N nodes. The tree nodes are numbered from  ...

  5. COT2 - Count on a tree II(树上莫队)

    COT2 - Count on a tree II You are given a tree with N nodes. The tree nodes are numbered from 1 to N ...

  6. 【BZOJ2588】Count On a Tree(主席树)

    [BZOJ2588]Count On a Tree(主席树) 题面 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第 ...

  7. 【SPOJ10707】 COT2 Count on a tree II

    SPOJ10707 COT2 Count on a tree II Solution 我会强制在线版本! Solution戳这里 代码实现 #include<stdio.h> #inclu ...

  8. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

  9. spoj COT2 - Count on a tree II

    COT2 - Count on a tree II http://www.spoj.com/problems/COT2/ #tree You are given a tree with N nodes ...

随机推荐

  1. Python实现发送邮件(实现单发/群发邮件验证码)

    Python smtplib 教程展示了如何使用 smtplib 模块在 Python 中发送电子邮件. 要发送电子邮件,我们使用 Python 开发服务器,Mailtrap 在线服务和共享的网络托管 ...

  2. java批量下载文件为zip包

    批量下载文件为zip包的工具类 package com.meeno.trainsys.util; import javax.servlet.http.HttpServletRequest; impor ...

  3. open62541(opcua)传输延迟探索小记

    缘起 将open62541作为中间件使用代替自定义数据的RPC,client通过订阅valueChange来接收数据.使用时发现有一些问题: 前后两次产生的数据相同时,不会触发valueChange ...

  4. VS 添加自定义--代码块 实现一秒创建方法

    创建一个方法 你是不是不可避免需要敲以下至少6行代码 现在教你一个方法 实现一秒创建完整方法 首先按照代码块规则创建代码块文件 代码块意义,是什么? 请参考: https://docs.microso ...

  5. 从0开始搭建一个IoC容器(C#版)

    网址:https://blog.csdn.net/wangyahua1234/article/details/100619695 目录 1. IoC简介 2. Tiny版IoC的功能 3. Tiny版 ...

  6. pyspark默认使用python2-----更改

    默认使用的竟然是2.7好烦如何解决呢 配置环境变量就行了 vi ~/.bashrc 添加一句话 export PATH=/home/hadoop/app/python3/bin:$PATH 保存退出  ...

  7. Linux centos 安装 Node.js

    官网下载地址 https://nodejs.org/zh-cn/download/ 1.下载二进制文件 (x64)   相当于  https://nodejs.org/dist/v10.16.3/no ...

  8. 单片机学习(九)定时器扫描按钮和数码管与PWM的使用

    目录 一.使用定时器扫描按钮和数码管 1. 使用定时器进行扫描的缘由 2. 定时器扫描独立按钮 3. 定时器扫描数码管 二.PWM的使用 1. PWM简介 2. LED呼吸灯 实现一 实现二 3. 按 ...

  9. 关于notepad++使用的那些事儿

    时间:2019-04-11 整理:PangYuaner 标题:Notepad++正则表达式语法 地址:https://www.cnblogs.com/kekec/p/5255475.html 标题:N ...

  10. 剑指 Offer 32 - III. 从上到下打印二叉树 III

    剑指 Offer 32 - III. 从上到下打印二叉树 III 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印, ...