bzoj2589【 Spoj 10707】 Count on a tree II
题目描述
输入格式
输出格式
题解
- 树上莫队;
- 如果不要求强制在线的话比较传统;
- 强制在线有点麻烦:
- 对树按深度分块,当一个点向下的深度超过$\sqrt{N}$就分一块;
- 这样分块保证了深度和块的数量在$O(\sqrt{N})$内,并且每一个块都是一颗子树;
- 预处理每个块的根对其他所有点的答案,这是$O(n\sqrt{N})$的时间和空间的;
- 考虑一个询问$u,v$如果在同一个块里则暴力查询;$O(\sqrt{N})$
- 否则假设$u$的根比$v$的根要深,否则交换;
- 利用预处理得到$(root_{u},v)$的答案$O(1)$,暴力查询$u$到$root_{u})$的颜色$O(\sqrt{N})$;
- 只需要查询某个颜色是否出现过;
- 可持久化块状链表记录$u$到原树的根链上的每个颜色出现的最大深度;$O(\sqrt{N})$
- 枚举的颜色没有出现过即查询颜色的最大深度一定小于$lca$的深度;
- 可持久化块状链表:
- 对颜色分块,记录每个历史版本每个块的起点;
- 插入的时候暴力复制上一个版本的起点,暴力新建一个修改位置的块并更新起点
#include<bits/stdc++.h>
using namespace std;
const int N=,M=;
int n,m,o=,hd[N],F[N],num[N],tot,sub[N],dep[N],rt,c[N],ans;
int B,sum[M][N],bl[N],cnt,len[N],Rt[M],sta[N],top;
int min(int x,int y){return x<y?x:y;}
int max(int x,int y){return x>y?x:y;}
struct Edge{int v,nt;}E[N<<];
char gc(){
static char*p1,*p2,s[];
if(p1==p2)p2=(p1=s)+fread(s,,,stdin);
return(p1==p2)?EOF:*p1++;
}
int rd(){
int x=,f=; char c=gc();
while(c<''||c>''){if(c=='-')f=-;c=gc();}
while(c>=''&&c<='')x=(x<<)+(x<<)+c-'',c=gc();
return x*f;
}
void adde(int u,int v){
E[o]=(Edge){v,hd[u]};hd[u]=o++;
E[o]=(Edge){u,hd[v]};hd[v]=o++;
}
namespace Block{
int l[N][M],a[N*M],Cnt,bl[N],B,st[M],ed[M],sz;
void init(){
B=sqrt(tot)+;
for(int i=;i<=tot;++i)bl[i]=(i-)/B+,a[i]=-;
sz=bl[tot];
for(int i=;i<=sz;++i){
l[][i]=st[i]=ed[i-]+;
ed[i]=ed[i-]+B;
}
ed[sz]=Cnt=tot;
}
int que(int u,int x){return a[l[u][bl[x]]+(x-)%B];}
void ins(int u,int x){
for(int i=;i<=sz;++i)l[u][i]=l[F[u]][i];
int len=ed[bl[x]]-st[bl[x]],tmp=l[u][bl[x]],pre=Cnt;
for(int i=;i<=len;++i)a[++Cnt]=a[tmp+i];
a[pre++(x-)%B]=dep[u];
l[u][bl[x]]=pre+;
}
}
void upd(int x,int y){
if((num[x]==)^(num[x]+y==))tot+=y;
num[x]+=y;
}
void dfs1(int u,int fa){
upd(c[u],);
sum[cnt][u]=tot;
for(int i=hd[u];i;i=E[i].nt)if(E[i].v!=fa)dfs1(E[i].v,u);
upd(c[u],-);
}
void dfs(int u,int fa){
int x=c[u];
F[u]=fa;
Block::ins(u,x);
sta[++top]=u;
for(int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==fa)continue;
dep[v]=dep[u]+;
dfs(v,u);
len[u]=max(len[v]+,len[u]);
}
if(len[u]>=B||u==){
len[u]=-;
Rt[++cnt]=u;
int v;do{
bl[v=sta[top--]]=cnt;
}while(v!=u);
dfs1(u,);
}
}
namespace LCA{
int son[N],tp[N],sz[N],F[N];
void dfs1(int u,int fa){
sz[u]=;son[u]=;F[u]=fa;
for(int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==fa)continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(int u,int T){
tp[u]=T;
if(son[u])dfs2(son[u],T);
for(int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==F[u]||v==son[u])continue;
dfs2(v,v);
}
}
int ask(int u,int v){
int tu=tp[u],tv=tp[v];
while(tu!=tv){
if(dep[tu]<dep[tv])v=F[tv],tv=tp[v];
else u=F[tu],tu=tp[u];
}
return dep[u]<dep[v]?u:v;
}
void init(){dfs1(,);dfs2(,);}
}
void query1(int u,int v){
int x=Rt[bl[u]],y=Rt[bl[v]],dz=dep[LCA::ask(u,v)];
if(dep[x]<dep[y])swap(x,y),swap(u,v);
ans=sum[bl[u]][v];
for(int w=u;w!=x;w=F[w]){
int d = max(Block::que(x,c[w]),Block::que(v,c[w]));
if(!num[c[w]]&&d<dz)num[c[w]]=,ans++;
}
for(int w=u;w!=x;w=F[w])num[c[w]]=;
printf("%d\n",ans);
}
void query2(int u,int v){
int dz=dep[LCA::ask(u,v)];
ans=;
for(int w=u;dep[w]>=dz;w=F[w])if(!(num[c[w]]++))ans++;
for(int w=v;dep[w]>=dz;w=F[w])if(!(num[c[w]]++))ans++;
for(int w=u;dep[w]>=dz;w=F[w])num[c[w]]=;
for(int w=v;dep[w]>=dz;w=F[w])num[c[w]]=;
printf("%d\n",ans);
}
int find(int x){
int l=,r=tot,mid;
while(l<r){
if(x<=sub[mid=l+r>>])r=mid;
else l=mid+;
}
return l;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("bzoj2589.in","r",stdin);
freopen("bzoj2589.out","w",stdout);
#endif
n=rd();m=rd();
B=sqrt(n)+;
for(int i=,x;i<=n;++i)c[i]=sub[i]=rd();
for(int i=,u,v;i<n;++i)adde(rd(),rd());
tot=n;sort(sub+,sub+tot+);
tot=unique(sub+,sub+tot+)-sub-;
for(int i=;i<=n;++i)c[i]=lower_bound(sub+,sub+tot+,c[i])-sub;
Block::init();
dep[]=-;
tot=;dfs(,);
LCA::init();
for(int i=,x,y;i<=m;++i){
x=rd()^ans,y=rd();
if(bl[x]!=bl[y])query1(x,y);
else query2(x,y);
}
return ;
}bzoj2589
bzoj2589【 Spoj 10707】 Count on a tree II的更多相关文章
- SPOJ 10707 COT2 - Count on a tree II
思路 树上莫队的题目 每次更新(u1,u2)和(v1,v2)(不包括lca)的路径,最后单独统计LCA即可 代码 #include <cstdio> #include <cstrin ...
- 【SPOJ】Count On A Tree II(树上莫队)
[SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...
- 主席树+LCA【p2633 (bzoj2588】 Count on a tree
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- 【bzoj2588/P2633】count on a tree —— LCA + 主席树
(以下是luogu题面) 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问 ...
- 【SPOJ QTREE4】Query on a tree IV(树链剖分)
Description 给出一棵边带权(\(c\))的节点数量为 \(n\) 的树,初始树上所有节点都是白色.有两种操作: C x,改变节点 \(x\) 的颜色,即白变黑,黑变白. A,询问树中最远的 ...
- SPOJ:COT2 Count on a tree II
题意 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. n=40000,m=100000 Sol 树上莫队模板题 # include <bits/stdc++.h ...
- 【BZOJ2589】 Spoj 10707 Count on a tree II
BZOJ2589 Spoj 10707 Count on a tree II Solution 吐槽:这道题目简直...丧心病狂 如果没有强制在线不就是树上莫队入门题? 如果加了强制在线怎么做? 考虑 ...
- 【BZOJ2589】[SPOJ10707]Count on a tree II
[BZOJ2589][SPOJ10707]Count on a tree II 题面 bzoj 题解 这题如果不强制在线就是一个很\(sb\)的莫队了,但是它强制在线啊\(qaq\) 所以我们就用到了 ...
- 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)
54 种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...
随机推荐
- Docker 入门之docker容器创建
使用docker容器的大多数人都是因为想要隔离不同运行环境的差异,使得自己的应用能更好的移植和部署.那么我们来看看掌握docker需要掌握哪些方面. 1,搭建docker环境 2,编译镜像并将其运行成 ...
- 下一代的DevOps服务:AIOps
AIOps是一个总称,用于指代使用复杂的基础设施管理软件和云解决方案监控工具来实现自动化数据分析和日常的DevOps操作. 那些10年前甚至是5年前构建的系统监控工具的主要缺陷是它们不是为了满足大数据 ...
- jobs命令详解
基础命令学习目录首页 在用管理员执行一个命令后,用Ctrl+Z把命令转移到了后台.导致无法退出root的. 输入命令:exit终端显示:There are stopped jobs. 解决方法:方法一 ...
- JSBridge的原理
前言 参考来源 前人栽树,后台乘凉,本文参考了以下来源 github-WebViewJavascriptBridge JSBridge-Web与Native交互之iOS篇 Ios Android Hy ...
- TeamWork#3,Week5,Bing Input Method vs Sogou Input Method
现在电脑上用五笔的用户越来越少了,好的拼音输入法也是难求.必应输入法的前身英库拼音输入法来自微软亚洲研究院的多项基础研究成果.最新的必应输入法不仅保留了英库拼音输入法的各项优势,还结合了必应的搜索体验 ...
- Daily Scrum (2015/10/29)
今天晚上我们学霸项目的三个小组在一起开会,讨论如何能在后期使我们三个项目更好地结合在一起.为了三个小组的能够同时工作,不出现某一小组因需要其他小组成果而停滞的情况,我们决定围绕lucene,solr, ...
- 【贪心算法】POJ-1328 区间问题
一.题目 Description Assume the coasting is an infinite straight line. Land is in one side of coasting, ...
- pktgen-dpdk 实战
官方手册:http://pktgen-dpdk.readthedocs.io/en/latest/getting_started.html 过程 开机(重启) 把DPDK那一套流程走一遍(环境变量设置 ...
- c# Parallel 并行运算 异步处理
var list = new List<string> { "https://www.baidu.com","https://associates.amazo ...
- Android之自定义View学习(一)
Android之自定义View学习(一) Canvas常用方法: 图片来源 /** * Created by SiberiaDante on 2017/6/3. */ public class Bas ...