BZOJ 3626 LCA 树链剖分
来源:互联网 发布:java实现多线程同步 编辑:程序博客网 时间:2024/06/05 08:08
题目链接:bzoj3626
题目大意:给出一个有根树,对于询问l,r,z,求出求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和
题解:
引用清华爷gconeice的题解
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1, r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i 到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT 均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log n),均可以完成任务。至此,题目已经被我们完美解决。
/************************************************************** Problem: 3626 User: cabinfever Language: C++ Result: Accepted Time:1724 ms Memory:7188 kb****************************************************************/ #include <cstdio>#include <string>#include <cmath>#include <cstring>#include <cstdlib>#include <algorithm>#include <iostream> using namespace std; const int maxn = 50010; struct edge{ int v,next;}e[maxn];int h[maxn],num = 0;int fa[maxn];int son[maxn];int pos[maxn];int top[maxn];int size[maxn];int n,m,cnt = 0;struct tree{ long long x,mark; int l,r;}t[maxn << 1];int tot = 0;struct Query{ int x,z,num; long long ans;}q[maxn << 1]; bool cmp1(Query a,Query b){ return a.num < b.num;} bool cmp2(Query a,Query b){ return a.x == b.x ? a.z < b.z : a.x < b.x;} void build_edge(int u,int v){ num++; e[num].v = v; e[num].next = h[u]; h[u] = num;} void build_tree(int x){ size[x] = 1; son[x] = 0; for(int i = h[x]; i; i = e[i].next) { build_tree(e[i].v); if(size[e[i].v] > size[son[x]]) son[x] = e[i].v; size[x] += size[e[i].v]; }} void split(int x){ if(son[fa[x]] == x) top[x] = top[fa[x]]; else { top[x] = x; for(int i = x; i; i = son[i]) pos[i] = ++cnt; } for(int i = h[x]; i; i = e[i].next) split(e[i].v);} void build(int p,int l,int r){ int mid = l + r >> 1; if(l == r) return; t[p].l = ++tot; t[p].r = ++tot; build(t[p].l,l,mid); build(t[p].r,mid+1,r);} void change(int p,int l,int r,int L,int R){ int mid = l + r >> 1; if(l == L && r == R) { t[p].x += r - l + 1; t[p].mark++; return; } if(t[p].mark) { t[t[p].l].x += (mid - l + 1) * t[p].mark; t[t[p].r].x += (r - mid) * t[p].mark; t[t[p].l].mark += t[p].mark; t[t[p].r].mark += t[p].mark; t[p].mark = 0; } if(R <= mid) change(t[p].l,l,mid,L,R); else if(L > mid) change(t[p].r,mid+1,r,L,R); else { change(t[p].l,l,mid,L,mid); change(t[p].r,mid+1,r,mid+1,R); } t[p].x = t[t[p].l].x + t[t[p].r].x;} long long getans(int p,int l,int r,int L,int R){ int mid = l + r >> 1; if(l == L && r == R) { return t[p].x; } if(t[p].mark) { t[t[p].l].x += (mid - l + 1) * t[p].mark; t[t[p].r].x += (r - mid) * t[p].mark; t[t[p].l].mark += t[p].mark; t[t[p].r].mark += t[p].mark; t[p].mark = 0; } if(R <= mid) return getans(t[p].l,l,mid,L,R); else if(L > mid) return getans(t[p].r,mid+1,r,L,R); return getans(t[p].l,l,mid,L,mid) + getans(t[p].r,mid+1,r,mid+1,R);} void updata(int x){ int fx = top[x]; while(x) { change(0,1,n,pos[fx],pos[x]); x = fa[fx]; fx = top[x]; }} long long query(int x){ long long ans = 0; int fx = top[x]; while(x) { ans += getans(0,1,n,pos[fx],pos[x]); x = fa[fx]; fx = top[x]; } return ans;} int main(){ cin >> n >> m; int x,y,z; for(int i = 2; i <= n; i++) { scanf("%d",&x); build_edge(x+1,i); fa[i] = x + 1; } build_tree(1); split(1); for(int i = 0; i < m; i++) { scanf("%d%d%d",&x,&y,&z); q[i*2].x = x; q[i*2].z = z+1; q[i*2].num = i*2; q[i*2+1].x = y+1; q[i*2+1].z = z+1; q[i*2+1].num = i*2+1; } sort(q,q+m*2,cmp2); build(0,1,n); int j = 0; for(int i = 0;i <= n; i++) { updata(i); while(q[j].x == i) { q[j].ans = query(q[j].z); j++; } } sort(q,q+m*2,cmp1); for(int i = 0; i < m; i++) printf("%lld\n",(q[i*2+1].ans - q[i*2].ans) % 201314); return 0;}
0 0
- BZOJ 3626 LCA 树链剖分
- BZOJ 3626 LCA 树链剖分
- bzoj 3626: [LNOI2014]LCA 树链剖分
- bzoj 3626: [LNOI2014]LCA 树链剖分
- BZOJ 3626 LNOI 2014 LCA 树链剖分
- BZOJ 3626 LNOI 2014 LCA 树链剖分
- 【BZOJ 3626】【LNOI 2014】LCA【树链剖分】
- BZOJ[3626][LNOI2014]LCA 树链剖分+线段树
- bzoj 3626: [LNOI2014]LCA
- 【BZOJ 3626】 [LNOI2014]LCA
- [bzoj 3626] LNOI2014 LCA
- bzoj 3626 LCA
- BZOJ 3626 [LNOI2014]LCA
- BZOJ 3626 [LNOI2014]LCA
- BZOJ 3626 [LNOI2014] LCA
- BZOJ 3626 [LNOI2014]LCA
- bzoj 3626 [LNOI2014]LCA
- BZOJ 3626 [LNOI2014]LCA
- S3C2440的寻址空间、存储控制器
- cocos2d-JS 实现 横 竖 屏 显示提示图片效果 !!!!!
- 怒被卡常
- 循环队列的简单实现
- 爬取网页动态数据
- BZOJ 3626 LCA 树链剖分
- noip运输计划(倍增lca,树上差分)
- 【python卡牌游戏】抽乌龟
- android:scrollbarStyle
- 【51nod 算法马拉松19 A】区间的价值 V2
- JAVA基础知识点(十一)--线程
- [LeetCode]Climbing Stairs
- access函数
- 进程的基本概念和进程控制