[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 son[maxn],father[maxn],id[maxn],cnt,deep[maxn],size[maxn],top[maxn];
  8 int res;
  9 inline int read(){
 10    int s=0,w=1;
 11    char ch=getchar();
 12    while(ch<=‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
 13    while(ch>=‘0‘&&ch<=‘9‘) s=s*10+ch-‘0‘,ch=getchar();
 14    return s*w;
 15 }
 16 inline void add(int x,int y){
 17     to[++e] = y;
 18     next[e] = begin[x];
 19     begin[x] = e;
 20 }
 21 inline void pushup(int root){
 22     tree[root] = tree[root<<1]+tree[root<<1|1];
 23 }
 24 inline void pushdown(int root,int pos){
 25     lazy[root<<1] += lazy[root];
 26     lazy[root<<1|1] += lazy[root];
 27     tree[root<<1] += lazy[root]*(pos-(pos>>1));
 28     tree[root<<1|1] += lazy[root]*(pos>>1);
 29     lazy[root] = 0;
 30 }
 31 inline void query(int root,int l,int r,int al,int ar){
 32     if(al <= l && ar >= r){
 33         res += tree[root];
 34         return;
 35     }
 36     if(lazy[root])pushdown(root,r-l+1);
 37     int mid = l+r>>1;
 38     if(al <= mid)query(root<<1,l,mid,al,ar);
 39     if(ar > mid)query(root<<1|1,mid+1,r,al,ar);
 40 }
 41 inline void update(int root,int l,int r,int al,int ar,int k){
 42     if(al <= l && ar >= r){
 43         lazy[root] += k;
 44         tree[root] += k*(r-l+1);
 45         return;
 46     }
 47     if(lazy[root])pushdown(root,r-l+1);
 48     int mid = l+r>>1;
 49     if(al <= mid)update(root<<1,l,mid,al,ar,k);
 50     if(ar > mid)update(root<<1|1,mid+1,r,al,ar,k);
 51     pushup(root);
 52 }
 53 inline void update_range(int x,int y,int k){
 54     while(top[x] != top[y]){
 55         if(deep[top[x]] < deep[top[y]])swap(x,y);
 56         update(1,1,n,id[top[x]],id[x],k);
 57         x = father[top[x]];
 58     }
 59     if(deep[x] > deep[y])swap(x,y);
 60     update(1,1,n,id[x],id[y],k);
 61 }
 62 inline void dfs1(int x,int fa,int dep){
 63     deep[x] = dep;
 64     father[x] = fa;
 65     size[x] = 1;
 66     int maxson = -1;
 67     for(int i = begin[x];i;i = next[i]){
 68         int y = to[i];
 69         if(y == fa)continue;
 70         dfs1(y,x,dep+1);
 71         size[x] += size[y];
 72         if(size[y] > maxson)son[x] = y,maxson = size[y];
 73     }
 74 }
 75 inline void dfs2(int x,int topf){
 76     id[x] = ++cnt;
 77     top[x] = topf;
 78     if(!son[x])return;
 79     dfs2(son[x],topf);
 80     for(int i = begin[x];i;i = next[i]){
 81         int y = to[i];
 82         if(y == father[x] || y == son[x])continue;
 83         dfs2(y,y);
 84     }
 85 }
 86 int main(){
 87     n = read();
 88     for(int i = 1;i <= n;i++)a[i] = read();
 89     for(int i = 1,x,y;i < n;i++){
 90         x = read();
 91         y = read();
 92         add(x,y);
 93         add(y,x);
 94     }
 95     dfs1(1,0,1);
 96     dfs2(1,1);
 97     for(int i = 1;i < n;i++){
 98         update_range(a[i],a[i+1],1);
 99         update_range(a[i+1],a[i+1],-1);
100     }
101     for(int i = 1;i <= n;i++)res = 0,query(1,1,n,id[i],id[i]),printf("%d\n",res);
102     return 0;
103 }

原文地址:https://www.cnblogs.com/wangyifan124/p/10312332.html

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

[JLOI2014]松鼠的新家-树链剖分的相关文章

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,

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

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

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],

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

【BZOJ 3631】 [JLOI2014]松鼠的新家

3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 681 Solved: 329 [Submit][Status][Discuss] Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在"树"上.松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的

[填坑]树上差分 例题:[JLOI2014]松鼠的新家(LCA)

今天算是把LCA这个坑填上了一点点,又复习(其实是预习)了一下树上差分.其实普通的差分我还是会的,树上的嘛,也是懂原理的就是没怎么打过. 我们先来把树上差分能做到的看一下: 1.找所有路径公共覆盖的边 例题:[NOIP2015]运输计划 (然而我还没过就先不讲了) 反正就是中间有一步要求一条边被所有计划公共覆盖. 那么怎么求它呢?暴力(滚粗).我们有一个非常好的方法就是树上差分(记录tmp为差分数组) 询问操作为从叶子节点的权值向上累加到root 在一条路径u→ v,如果tmp[u]++,那么我

【洛谷】【lca+树上差分】P3258 [JLOI2014]松鼠的新家

[题目描述:] 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n(2 ≤ n ≤ 300000)个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家.可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞.可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃. 维尼是个馋家伙,立马就

P3258 [JLOI2014]松鼠的新家

P3258 [JLOI2014]松鼠的新家倍增lca+树上差分,从叶子节点向根节点求前缀和,dfs求子树和即可,最后,把每次的起点和终点都. 1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<algorithm> 5 #include<cmath> 6 #include<ctime> 7 #include<set> 8 #include