1. 程式人生 > >[BZOJ3626][LNOI2014]LCA

[BZOJ3626][LNOI2014]LCA

+= make input lca sta getchar tor pla return

BZOJ
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。

sol

ppl跟我講這個東西叫做“奇技淫巧”,一看這種東西就應該是ppl這種人說的吧
所謂“奇技淫巧”在前面的一道題裏面講過,給個鏈接HNOI2015開店
就是說,要求的\(dis_{lca}\),就是兩點鏈交的長度。
那麽對於一個詢問\(l_i\),\(r_i\),\(z_i\),我們只要把\(l_i\)\(r_i\)的點在樹上做一個到根的路徑覆蓋(路徑上權值全部加1),再查一下\(z_i\)到根的權值和就行了。
發現可離線,把所有詢問輸入後按\(l_i\)

或是\(r_i\)排序,然後做就可以了呀。
樹鏈剖分\(O(nlog^2n)\)小常數,\(Link - cut\)\(O(nlogn)\)大常數
所以應該還是樹剖要快一點吧

code

因為以前沒寫過帶標記的LCT所以就交了一發LCT

#include<cstdio>
#include<algorithm>
using namespace std;
const int mod = 201314;
const int N = 50005;
int n,m,fa[N],ls[N],rs[N],rev[N],sz[N],val[N],sum[N],pls[N],Stack[N],top,ans[N];
struct
query{ int id,z,pos,opt; bool operator < (const query &b) const {return pos<b.pos;} }q[N<<1]; int gi() { int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;} void pushup(int x) { sz[x]=sz[ls[x]]+sz[rs[x]]+1; sum[x]=(sum[ls[x]]+sum[rs[x]]+val[x])%mod; } void reverse(int x){swap(ls[x],rs[x]);rev[x]^=1;} void cover(int x,int num) { (val[x]+=num)%=mod; (sum[x]+=1ll*sz[x]*num%mod)%=mod; (pls[x]+=num)%=mod; } void pushdown(int x) { if (rev[x]) { if (ls[x]) reverse(ls[x]); if (rs[x]) reverse(rs[x]); rev[x]=0; } if (pls[x]) { if (ls[x]) cover(ls[x],pls[x]); if (rs[x]) cover(rs[x],pls[x]); pls[x]=0; } } void R_rotate(int x) { int y=fa[x],z=fa[y]; ls[y]=rs[x]; if (rs[x]) fa[rs[x]]=y; fa[x]=z; if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x; rs[x]=y;fa[y]=x; pushup(y); } void L_rotate(int x) { int y=fa[x],z=fa[y]; rs[y]=ls[x]; if (ls[x]) fa[ls[x]]=y; fa[x]=z; if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x; ls[x]=y;fa[y]=x; pushup(y); } void splay(int x) { Stack[top=1]=x; for (int i=x;!isroot(i);i=fa[i]) Stack[++top]=fa[i]; while (top) pushdown(Stack[top--]); while (!isroot(x)) { int y=fa[x],z=fa[y]; if (isroot(y)) if (x==ls[y]) R_rotate(x); else L_rotate(x); else if (y==ls[z]) if (x==ls[y]) R_rotate(y),R_rotate(x); else L_rotate(x),R_rotate(x); else if (x==ls[y]) R_rotate(x),L_rotate(x); else L_rotate(y),L_rotate(x); } pushup(x); } void access(int x){for (int y=0;x;y=x,x=fa[x]) splay(x),rs[x]=y,pushup(x);} void makeroot(int x){access(x);splay(x);reverse(x);} void split(int x,int y){makeroot(x);access(y);splay(y);} void link(int x,int y){makeroot(x);fa[x]=y;} int main() { n=gi();m=gi(); for (int i=2;i<=n;i++) { int u=gi()+1; link(u,i); } for (int i=1;i<=m;i++) { int l=gi()+1,r=gi()+1,u=gi()+1; q[i]=(query){i,u,l-1,-1}; q[i+m]=(query){i,u,r,1}; } sort(q+1,q+2*m+1); int j=1; while (!q[j].pos&&j<=2*m) ++j; for (int i=1;i<=n;i++) { split(i,1); cover(1,1); while (j<=2*m&&q[j].pos==i) { split(q[j].z,1); ans[q[j].id]=(ans[q[j].id]+q[j].opt*sum[1]%mod+mod)%mod; ++j; } } for (int i=1;i<=m;i++) printf("%d\n",ans[i]%mod); return 0; }

[BZOJ3626][LNOI2014]LCA