当前位置: 代码迷 >> 综合 >> bzoj 3626 LCA (树链剖分)
  详细解决方案

bzoj 3626 LCA (树链剖分)

热度:34   发布时间:2023-12-17 03:29:47.0

题意:

思路:

比较有意思的树链剖分
首先对于两个点lca的深度,我们发现就是两点和根的连线的重叠部分,那么我们就可以先把一个点到根的所有点都染下色,再用另一个点去查看到根有几个点被染色了
然后想怎么处理那么多区间,根据之前说的,我们可以把[l,r]中所有的点都看作第一个点,z看作第二个点,这样我们离线了提问,然后一边把点放进去一边查询即可

错误及反思:

l是可以为0的,bzoj有时候数据不会给的很细致

代码:

#include<bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
const int N = 50100;
const int mod= 201314;struct edge{int to,next;
}e[N*2];vector<int> ans[N];
vector<pair<int,int> > need[N];
int segtree[N*4],lazy[N*4];
int tot,tid,q,n;
int top[N],si[N],fa[N],first[N],son[N],depth[N],id[N],val[N],rnk[N];void addedge(int x,int y){e[tot].to=y;e[tot].next=first[x];first[x]=tot++;e[tot].to=x;e[tot].next=first[y];first[y]=tot++;
}void dfs1(int now,int bef,int dep){fa[now]=bef;depth[now]=dep;si[now]=1;for(int i=first[now];i!=-1;i=e[i].next)if(e[i].to!=bef){dfs1(e[i].to,now,dep+1);si[now]+=si[e[i].to];if(son[now]==-1) son[now]=e[i].to;else son[now]=si[e[i].to]>si[son[now]]?e[i].to:son[now];}
}void dfs2(int now,int tp){top[now]=tp;id[now]=tid++;if(son[now]!=-1) dfs2(son[now],tp);for(int i=first[now];i!=-1;i=e[i].next)if(e[i].to!=fa[now]&&e[i].to!=son[now])dfs2(e[i].to,e[i].to);
}void init(){tot=0; tid=0;memset(first,-1,sizeof(first));memset(son,-1,sizeof(son));
}void pushup(int rt){segtree[rt]=segtree[rt<<1]+segtree[rt<<1|1];
}void pushdown(int l,int r,int rt){if(lazy[rt]){int m=(l+r)/2;segtree[rt<<1]+=(m-l+1)*lazy[rt];segtree[rt<<1]%=mod;lazy[rt<<1]+=lazy[rt];lazy[rt<<1]%=mod;segtree[rt<<1|1]+=(r-m)*lazy[rt];segtree[rt<<1|1]%=mod;lazy[rt<<1|1]+=lazy[rt];lazy[rt<<1|1]%=mod;lazy[rt]=0;}
}void add(int L,int R,int l,int r,int rt){if(L<=l&&R>=r){segtree[rt]+=r-l+1;segtree[rt]%=mod;lazy[rt]++;lazy[rt]%=mod;return ;}pushdown(l,r,rt);int m=(l+r)/2;if(m>=L) add(L,R,lson);if(m<R) add(L,R,rson);pushup(rt);
}int query(int L,int R,int l,int r,int rt){if(L<=l&&R>=r)return segtree[rt];pushdown(l,r,rt);int m=(l+r)/2;int ans=0;if(m>=L) ans+=query(L,R,lson);ans%=mod;if(m<R) ans+=query(L,R,rson);ans%=mod;pushup(rt);return ans;
}
int cal(int L,int R){int f1=top[L],f2=top[R];int ans=0;while(f1!=f2){if(depth[f1]<depth[f2]){swap(f1,f2);swap(L,R);}ans+=query(id[f1],id[L],0,tid-1,1);ans%=mod;L=fa[f1];f1=top[L];}if(depth[L]>depth[R]) swap(L,R);ans+=query(id[L],id[R],0,tid-1,1);ans%=mod;return ans;
}
void up(int L,int R){int f1=top[L],f2=top[R];while(f1!=f2){if(depth[f1]<depth[f2]){swap(f1,f2);swap(L,R);}add(id[f1],id[L],0,tid-1,1);L=fa[f1];f1=top[L];}if(depth[L]>depth[R]) swap(L,R);add(id[L],id[R],0,tid-1,1);
}
int main(){init();scanf("%d%d",&n,&q);for(int i=1,u;i<n;i++){scanf("%d",&u);addedge(u,i);}dfs1(0,0,1);dfs2(0,0);for(int i=1;i<=n;i++) rnk[id[i]]=i;for(int i=0;i<q;i++){int ta,tb,tc; scanf("%d%d%d",&ta,&tb,&tc);if(ta)need[ta-1].push_back(make_pair(tc,i));elseans[i].push_back(0);need[tb].push_back(make_pair(tc,i));}for(int i=0;i<n;i++){up(0,i);for(int j=0;j<need[i].size();j++){int an=cal(0,need[i][j].fi);ans[need[i][j].se].push_back(an);}}for(int i=0;i<q;i++){if(ans[i][1]<ans[i][0])printf("%d\n",ans[i][1]+mod-ans[i][0]);elseprintf("%d\n",ans[i][1]-ans[i][0]);}
}