BZOJ3631: [JLOI2014]松鼠的新家 树链剖分/lca/树上查分

求n次lca后树上差分。

每次移动时在起始点和终点各打一个start标记,在LCA和LCA的父节点处各上打一个end标记,然后深搜,start标记一直上传,遇到end标记就停止,最后再处理一下就行

% PoPoQQQ大爷

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define N 310000
using namespace std;
int head[N],dep[N],sz[N],son[N],fa[N],a[N],top[N],tot,n,p,q,s[N],ans[N],start[N],end[N];
struct node {
     int to,next;
}e[N<<1];
inline void ins(int u,int v) {
     e[++tot].to=v; e[tot].next=head[u]; head[u]=tot;
}
inline int in() {
     int x=0,ch=getchar();
     while(ch<‘0‘ || ch>‘9‘) ch=getchar();
     while(ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar();
     return x;
}
void dfs(int x,int pre) {
     dep[x]=dep[fa[x]=pre]+1; sz[x]=1;
     for(int k=head[x];k;k=e[k].next) if(e[k].to!=pre){
          dfs(e[k].to,x);
          sz[x]+=sz[e[k].to];
          if(sz[e[k].to]>sz[son[x]]) son[x]=e[k].to;
     }
}
void dfs1(int x,int chain) {
     top[x]=chain;
     if(son[x]) dfs1(son[x],chain);
     for(int k=head[x];k;k=e[k].next) if(e[k].to!=fa[x]&&e[k].to!=son[x]) dfs1(e[k].to,e[k].to);
}
int lca(int x,int y) {
     int a=top[x],b=top[y];
     while(a!=b) {
          if(dep[a]<dep[b]) swap(a,b),swap(x,y);
          x=fa[a]; a=top[x];
     }
     if(dep[x]<dep[y])return x; else return y;
}
int getans(int x) {
     int sum=start[x];
     for(int k=head[x];k;k=e[k].next) if(e[k].to!=fa[x]) sum+=getans(e[k].to);
     sum-=end[x];
     return ans[x]=sum;
}
int main () {
    n=in();
    rep(i,1,n) a[i]=in();
    rep(i,1,n-1) p=in(),q=in(),ins(p,q),ins(q,p); ins(0,1); ins(1,0);
    dfs(1,0);  dfs1(1,1);
    rep(i,1,n-1) {
        int c=lca(a[i],a[i+1]);
        start[a[i]]++; start[a[i+1]]++; end[c]++; end[fa[c]]++;
    }
    getans(1);
    rep(i,1,n) printf("%d\n",ans[i]-(i!=a[1]));
}
  

时间: 2024-10-16 22:27:36

BZOJ3631: [JLOI2014]松鼠的新家 树链剖分/lca/树上查分的相关文章

BZOJ 3631 JLOI2014 松鼠的新家 树链剖分/LCA

题目大意:给定一棵无根树和一个序列,在这个序列上依次遍历,求每个点的访问次数(最后一个点的访问次数要-1) 树链剖分的裸题--考场上我还是一个弱渣,啥也不会,暴力得了50分,剩下两道题爆零了...而且30W深搜爆栈,人生第一次手写了系统栈.. 回来因为这题的原因去学了树链剖分 结果没学明白 每条重链单独开了一棵线段树 常数大的要死 高一时写的代码...还是别看了,拿去对拍可以,阅读性欠佳 #include<stdio.h> #include<stdlib.h> #include&l

BZOJ 3631: [JLOI2014]松鼠的新家( 树链剖分 )

裸树链剖分... ------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; const int maxn = 300009; struct edge { int to; edge* next; } E[maxn << 1], *pit = E, *head[maxn]; inline void add(int u,

[JLOI2014]松鼠的新家-树链剖分

最开始的时候我在写线段树部分的时候还打了一个build,后来一想,打个球球大作战的build啊!!!有个锤子的用啊!!! 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 3e6+5; 4 int n; 5 int e,begin[maxn],next[maxn],to[maxn],a[maxn]; 6 int tree[maxn<<2],lazy[maxn<<2]; 7 int so

BZOJ3631 松鼠的新家(树链剖分)

题目链接 松鼠的新家 差不多可以说是树链剖分的模板题了,直接维护即可. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i,n) for(int i(0); i < (n); ++i) 6 #define rep(i,a,b) for(int i(a); i <= (b); ++i) 7 #define dec(i,a,b) for(int i(a); i >= (b); --i) 8 #

[JLOI2014]松鼠的新家 (树剖)

题目 P3258 [JLOI2014]松鼠的新家 解析 非常裸的一道树剖题 链上修改+单点查询的板子 记录一下所经过的点\(now[i]\),每次更新\(now[i-1]到now[i]\) 我们链上更新时上一次到的终点,是这一次一次更新的起点,又因为在\(a_n\)处可以不放糖,所以我们每次链上更新完成后,在这条链的终点位置处糖数\(-1\). 然后套板子直接做 代码 #include <bits/stdc++.h> using namespace std; const int N = 2e6

bzoj3631: [JLOI2014]松鼠的新家(LCA+差分)

题目大意:一棵树,以一定顺序走完n个点,求每个点经过多少遍 可以树链剖分,也可以直接在树上做差分序列的标记 后者打起来更舒适一点.. 具体实现: 先求x,y的lca,且dep[x]<dep[y], 如果在一棵子树下的一条链上,那么lca就是x 则g[fa[x]]--; g[y]++; 如果在一棵子树的两条分枝上,那么lca设为z g[x]++, g[y]++, g[z]--, g[fa[z]]-- 最后从叶子节点加回根节点,加法是差分序列的那种加法 因为z会加左右两边,多加了1,所以要减去. 1

【树链剖分】【树状数组】【最近公共祖先】【块状树】bzoj3631 [JLOI2014]松鼠的新家

裸题,树状数组区间修改+单点查询.当然要稍微讨论一下链的左右端点是否修改的情况咯. #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 300001 int en,v[N<<1],first[N],next[N<<1],n; void AddEdge(const int &U,const int &V) { v[++

BZOJ3631[JLOI2014]松鼠的新家 题解

题目大意: 给你一棵树,要从编号为a[1]的节点走到编号为a[2]的节点再走到编号为a[3]的节点……一直走到编号为a[n]的节点.问每个节点最少访问多少次. 思路: 将其进行轻重链剖分,则从a[i]走到a[i+1]实际上就是在几段重链的节点上+1,于是就用线段树来维护一下即可. 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #d

BZOJ3631: [JLOI2014]松鼠的新家

传送门 树上的差分优化,很简单的一道题,应该属于NOIP2015TGD2T3的子问题. //BZOJ 3631 //by Cydiater //2016.10.25 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <ctime> #include <cstring> #include <string> #i