首页 > 其他分享 >树上莫队

树上莫队

时间:2023-10-12 21:11:45浏览次数:36  
标签:head int st ++ lca 树上 莫队

20231012

树上莫队

由于联考考到,又直接爆0,于是来学习。

树上莫队——把莫队放到树上。

但我是真的不知道把莫队怎么放到树上。。。

于是我们考虑一个东西叫做欧拉序

就是再 dfs 的时候在进栈和出栈的地方都记录一下。

而在区间查询的时候,我们只对区间出现一次的数统计答案,

用一个数组维护即可,就是每次改变 \(\oplus 1\)。

而对于每一次 \(u,v\) ,

如果在一个子树之内,我们就从 \(st[u]\) 查到 \(st[v]\),

反之,从 \(ed[u]\) 查到 \(st[v]\) 即可。

注意对于不在同一棵子树中的,

需要把 lca 的贡献加上。

SP10707 模板题

#include <bits/stdc++.h>
using namespace std;

const int N=4e4+5,M=1e5+5;
int bl,n,m,a[N],b[N],len,l,r,vis[N],c[N],cnt=0,top[N],st[N],ans[M],ed[N],idx=0,dep[N],sq[M],fa[N],son[N],siz[N],head[N],tot=0;
struct edge{
  int v,nxt;
}e[N<<1];
struct node{
  int l,r,u,v,bl,id,lca;
  bool operator <(const node &rhs) const{
  	if(bl!=rhs.bl) return bl<rhs.bl;
  	return r<rhs.r;
  }
}q[M];

int read(){
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
  while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f; 
} 

void print(int x){
  int p[15],tmp=0;
  if(x==0) putchar('0');
  if(x<0) putchar('-'),x=-x;
  while(x){
    p[++tmp]=x%10;
    x/=10;
  }
  for(int i=tmp;i>=1;i--) putchar(p[i]+'0');
  putchar('\n');
}

void add(int u,int v){
  e[++tot]=(edge){v,head[u]};
  head[u]=tot;
  e[++tot]=(edge){u,head[v]};
  head[v]=tot;
}

void dfs1(int u,int pre){
  fa[u]=pre,siz[u]=1;son[u]=-1;dep[u]=dep[pre]+1;
  st[u]=++idx;sq[idx]=u;
  for(int i=head[u];i;i=e[i].nxt){
  	int v=e[i].v;
  	if(v==pre) continue;
  	dfs1(v,u);
  	if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;
  	siz[u]+=siz[v];
  }
  ed[u]=++idx;sq[idx]=u;
}

void dfs2(int u,int pre){
  top[u]=pre;
  if(son[u]==-1) return ;
  dfs2(son[u],pre);
  for(int i=head[u];i;i=e[i].nxt){
  	int v=e[i].v;
  	if(v==fa[u]||v==son[u]) continue;
  	dfs2(v,v); 
  }
}

int lca(int u,int v){
  while(top[u]!=top[v]){
  	if(dep[top[u]]<dep[top[v]]) swap(u,v);
	u=fa[top[u]]; 
  }
  if(dep[u]>dep[v]) swap(u,v);
  return u;
}

void upd(int i){cnt+=(++c[a[i]]==1);}
void del(int i){cnt-=(--c[a[i]]==0);}
void wrk(int i){
  if(vis[i]) del(i);
  else upd(i);
  vis[i]^=1;
}

int main(){
  /*2023.10.12 H_W_Y SP10707 COT2 - Count on a tree II 树上莫队*/ 
  n=read();m=read();
  for(int i=1;i<=n;i++) a[i]=read(),b[i]=a[i];
  sort(b+1,b+n+1);
  len=unique(b+1,b+n+1)-b-1;
  for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+len+1,a[i])-b;
  for(int i=1,u,v;i<n;i++) u=read(),v=read(),add(u,v);
  dfs1(1,0);dfs2(1,1);bl=sqrt((n<<1));
  for(int i=1;i<=m;i++){
  	q[i].u=read();q[i].v=read();q[i].id=i;
  	int &u=q[i].u,&v=q[i].v;q[i].lca=lca(u,v);
  	if(st[u]>st[v]) swap(u,v);
  	if(u==q[i].lca) q[i].l=st[u],q[i].r=st[v],q[i].bl=st[u]/bl,q[i].lca=0;
  	else q[i].l=ed[u],q[i].r=st[v],q[i].bl=ed[u]/bl;
  }
  sort(q+1,q+m+1);l=1,r=0;
  for(int i=1;i<=m;i++){
  	while(q[i].r>r) wrk(sq[++r]);
  	while(q[i].l<l) wrk(sq[--l]);
  	while(q[i].r<r) wrk(sq[r--]);
  	while(q[i].l>l) wrk(sq[l++]);
  	if(q[i].lca) wrk(q[i].lca);
  	ans[q[i].id]=cnt;
  	if(q[i].lca) wrk(q[i].lca);
  }
  for(int i=1;i<=m;i++) print(ans[i]);
  return 0;
}

标签:head,int,st,++,lca,树上,莫队
From: https://www.cnblogs.com/hwy0622/p/17760583.html

相关文章

  • 树上的最大权连通块:一种换根动态规划与贪心算法的结合
    树上的最大权连通块:一种换根动态规划与贪心算法的结合在计算机科学中,树是一种非常特殊的数据结构,不仅因为它们在存储数据时的效率,还因为它们提供了一种非常直观且强大的方式来解决各种问题。今天,我们将探讨一种特殊类型的问题,即在一棵树中找到一个特殊的子集或连通块,该子集中的节......
  • 6577: 暗的连锁 LCA+树上差分
    描述  Dark是一张无向图,图中有N个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark有N–1条主要边,并且Dark的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark还有M条附加边。你的任务是把Dark斩为不连通的两部分。一开始Dark的附加边......
  • 二次离线莫队笔记
    前言莫队可以解决许多其他数据结构无法完成的问题,正在很多其他问题上也可以拿部分分甚至满分,只因其复杂度为小常数\(O(n\sqrtn\timesk)\)其中\(k\)是单次扩张以及收缩的复杂度,而二离莫队可以在答案可差分的情况下达到\(O(n\sqrtn+n\timesk)\)起源lxl把二次离线莫......
  • 在线莫队
    我竟然独立发现了这个东西...考虑普通的莫队就是让区间加元素操作尽可能少,那么对于所谓的在线莫队,我们可以先跑出一些标准区间的值,然后在对他进行拓展,最终得出结果。我们均匀的取出\(B\)个关键点,然后对于两两关键点算出答案。那么我们拓展区间时,最多要拓展\(O(\frac{n^2}{B})......
  • 图论——树上问题 学习笔记
    图论——树上问题学习笔记目录树的直径树的重心树的中心经典问题1:最小化最大距离树的直径定义树上任意两节点之间最长的简单路径即为树的直径。显然,一棵树可以有多条直径,他们的长度相等。性质若树上所有边边权均为正,则树的所有直径有交,且中点重合;有树的直径\((p,q......
  • awa(树上邻域数颜色)
    虚树+DP+树剖+二维数点题意:给一棵树,每个点有一个颜色,多次查询给定\(x,d\),询问树上距离某个点\(x\)小于等于\(d\)的所有点的颜色个数,这些点显然形成一个连通块。先将询问离线,考虑对于每个点,求出每个颜色对这个点的最小距离,考虑二维数点,来计算出\(\led\)的颜色的数......
  • P2664 树上游戏
    P2664树上游戏解法一:淀粉的另一种形式。正常淀粉求得是每条路径,此题要求每个点为端点的所有路径,所以处理当前连通块时不仅要考虑根的答案,也要考虑根的子树对另一棵子树的影响。解法二:考虑颜色的贡献。跳出对点的答案的计算,思考每种颜色分别的贡献。对于每种颜色,\(i\)对于\(......
  • 【主席树】P8201 [传智杯 #4 决赛] [yLOI2021] 生活在树上(hard version)题解
    P8201简单题。题中求的是\(dis_{a,t}\oplusdis_{t,b}=k\)是否存在,显然不好直接维护,考虑转化。令\(dist=dis_{a,t}\oplusdis_{t,b}\),\(val=\bigoplus\limits_{x\in\text{path}(a,b)}w_x\)。如果\(t\)在\(\text{path}(a,b)\)上,则\(dist=val\oplus......
  • 反思---树上LIS
    反思---树上LIS题目描述给你一棵n个节点的树,树的每个节点上都有一个值a[i]。现在要您求出从1号点到i号点的最短路径上最长上升子序列的长度。就是单调栈优化+dfs回溯对比两段代码的dfs部分://ACCodeinlinevoiddfs(intu,intf){ intw=lower_bound(b+1,b+l+1,a[......
  • SDU Open 2023-F、树上随机游走
    SDUOpen2023-F、树上随机游走题目:https://codeforces.com/group/2altttv8oU/contest/477604/problem/F题意:给定一棵\(n\)个点的无根树,在树上随机游走(即每次会从当前点等概率地走到一个相邻结点),\(q\)次询问,每次问从\(s\)走到\(t\)的期望步数。\(1\leqn,q\leq2\times......