[BZOJ3626][LNOI2014][树链剖分][差分][离线处理]LCA
2016-11-13 22:10
495 查看
Description
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
Input
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input
5 2
0
0
1
1
1 4 3
1 4 2
Sample Output
8
5
HINT
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
题目名字叫LCA,其实跟LCA并没有什么关系,因为如果5e4个询问对每个点依次求LCA肯定要GG
我们首先来看LCA深度的另一种求法,假设我们要dep[LCA(u,v)],那么可以在u到根节点的所有点打上标记(权值加1),然后再统计出v到根节点的路径上的sum,这个即是要求得dep[LCA(u,v)]
不难发现,这个算法是可以叠加的,即对于询问[L,R,goal],我们可以将[L,R]的点到根的路径都打上标记,再同级goal到跟的标记总数,即为单次询问答案
那么单次询问就可以用树链剖分来处理了,时间复O(nlog*logn),再加上q次询问,显然还是无法承受
又可以想到,对于一次询问,我们是可以差分的,即ans=[1,R,goal]-[1,L-1,goal],那现在就可以进行离线处理了
从1-n不断打标记,并将询问排好序后看当前是否有询问需要处理
问题就可以解决了
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
Input
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input
5 2
0
0
1
1
1 4 3
1 4 2
Sample Output
8
5
HINT
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
题目名字叫LCA,其实跟LCA并没有什么关系,因为如果5e4个询问对每个点依次求LCA肯定要GG
我们首先来看LCA深度的另一种求法,假设我们要dep[LCA(u,v)],那么可以在u到根节点的所有点打上标记(权值加1),然后再统计出v到根节点的路径上的sum,这个即是要求得dep[LCA(u,v)]
不难发现,这个算法是可以叠加的,即对于询问[L,R,goal],我们可以将[L,R]的点到根的路径都打上标记,再同级goal到跟的标记总数,即为单次询问答案
那么单次询问就可以用树链剖分来处理了,时间复O(nlog*logn),再加上q次询问,显然还是无法承受
又可以想到,对于一次询问,我们是可以差分的,即ans=[1,R,goal]-[1,L-1,goal],那现在就可以进行离线处理了
从1-n不断打标记,并将询问排好序后看当前是否有询问需要处理
问题就可以解决了
#include<cstring> #include<cstdio> #include<algorithm> #include<cctype> using namespace std; const int maxn=5e4+5; const int mod=201314; int n,m,cnt,edge,cur,ans[maxn]; int to[maxn],nxt[maxn],head[maxn]; int fa[maxn],son[maxn],size[maxn],dfn[maxn],top[maxn]; struct Data { int pos,order,flag,goal; bool operator<(const Data &x)const { return pos<x.pos; } }data[maxn<<1]; struct Seg { int L,R,sum,lazy; }seg[maxn<<2]; #define L(x) seg[x].L #define R(x) seg[x].R #define sum(x) seg[x].sum #define lazy(x) seg[x].lazy #define Lson(x) (x<<1) #define Rson(x) (x<<1|1) int readint() { int x=0; char ch=getchar(); while (!isdigit(ch)) ch=getchar(); while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();} return x; } void edge_add(int u,int v) { to[++edge]=v; nxt[edge]=head[u]; head[u]=edge; } void dfs1(int u) { size[u]=1; for (int E=head[u];E;E=nxt[E]) { int v=to[E]; if (v==fa[u]) continue; dfs1(v); size[u]+=size[v]; if (size[v]>size[son[u]]) son[u]=v; } } void dfs2(int u,int tp) { top[u]=tp; dfn[u]=++cnt; if (son[u]) dfs2(son[u],tp); for (int E=head[u];E;E=nxt[E]) { int v=to[E]; if (v==fa[u]||v==son[u]) continue; dfs2(v,v); } } void build(int s,int t,int tr) { L(tr)=s; R(tr)=t; if (s==t) return ; int mid=(s+t)>>1; build(s,mid,Lson(tr)); build(mid+1,t,Rson(tr)); } void pushup(int tr) { sum(tr)=(sum(Lson(tr))+sum(Rson(tr)))%mod; } void pushdown(int tr) { lazy(Lson(tr))+=lazy(tr); lazy(Rson(tr))+=lazy(tr); sum(Lson(tr))+=lazy(tr)*(R(Lson(tr))-L(Lson(tr))+1); sum(Lson(tr))%=mod; sum(Rson(tr))+=lazy(tr)*(R(Rson(tr))-L(Rson(tr))+1); sum(Rson(tr))%=mod; lazy(tr)=0; } void update2(int s,int t,int tr) { if (s==L(tr)&&t==R(tr)) { sum(tr)+=t-s+1; sum(tr)%=mod; lazy(tr)++; return ; } pushdown(tr); int mid=(L(tr)+R(tr))>>1; if (t<=mid) update2(s,t,Lson(tr)); else if (s>=mid+1) update2(s,t,Rson(tr)); else update2(s,mid,Lson(tr)),update2(mid+1,t,Rson(tr)); pushup(tr); } void update1(int u) { while (top[u]^1) { update2(dfn[top[u]],dfn[u],1); u=fa[top[u]]; } update2(1,dfn[u],1); } int query2(int s,int t,int tr) { if (s==L(tr)&&t==R(tr)) return sum(tr); pushdown(tr); int mid=(L(tr)+R(tr))>>1; if (t<=mid) return query2(s,t,Lson(tr)); if (s>=mid+1) return query2(s,t,Rson(tr)); return query2(s,mid,Lson(tr))+query2(mid+1,t,Rson(tr)); } int query1(int u) { int ret=0; while (top[u]^1) { ret+=query2(dfn[top[u]],dfn[u],1); ret%=mod; u=fa[top[u]]; } ret+=query2(1,dfn[u],1); return ret%mod; } int main() { n=readint(); m=readint(); for (int i=2;i<=n;i++) fa[i]=readint(),edge_add(++fa[i],i); dfs1(1); dfs2(1,1); build(1,n,1); for (int i=1;i<=m;i++) { int u=((i-1)<<1)+1,v=u+1; data[u].pos=readint(); data[v].pos=readint()+1; data[u].goal=data[v].goal=readint()+1; data[u].order=data[v].order=i; data[u].flag=-1; data[v].flag=1; } sort(data,data+(m<<1|1)); for (int i=1;i<=(m<<1);i++) { if (!data[i].pos) continue; while (cur<data[i].pos) { cur++; update1(cur); } ans[data[i].order]+=(query1(data[i].goal)*data[i].flag); } for (int i=1;i<=m;i++) printf("%d",(ans[i]+mod)%mod),putchar('\n'); return 0; }
相关文章推荐
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
- [BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】
- 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树
- BZOJ 3626: [LNOI2014]LCA 树链剖分 询问差分
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
- BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )
- 3626: [LNOI2014]LCA (树链剖分+离线处理)
- bzoj 3626: [LNOI2014]LCA 离线+树链剖分
- 【BZOJ3626】LCA(树上差分,树链剖分)
- BZOJ 3626 [LNOI2014]LCA - 树链剖分+线段树结构+玄学离散
- BZOJ 3626 [LNOI2014]LCA 树链剖分 离线+差分
- bzoj 3626 树链剖分+离线处理
- bzoj 3626: [LNOI2014]LCA 树链剖分
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
- BZOJ[3626][LNOI2014]LCA 树链剖分+线段树
- BZOJ 3626 [LNOI2014]LCA ——树链剖分
- [bzoj3626][LNOI2014]LCA 树链剖分
- 【树链剖分】【线段树】bzoj3626 [LNOI2014]LCA
- bzoj3626: [LNOI2014]LCA 树链剖分
- bzoj 3626: [LNOI2014]LCA 树链剖分