[LNOI 2014] LCA
题目传送-Luogu4211
题目传送-BZOJ3626
题意:
给你一棵\(n\)个节点的树,定义一个点的深度为它到1号节点的距离+1
有\(q\)次询问,每次给出\((l,r,p)\),求\(\sum_{i=l}^rdep(LCA(i,p))\)
题解:
考虑计算LCA(x,y),我们把x->1经过的节点权值+1,那么答案就是y->1经过的权值和,这东西可以前缀一下,然后答案就是\(sum_r-sum_{l-1}\)
这个可以用离线+树剖搞出来
过程:
树剖写错了O(1)次
还忘了取模。。
代码:
const int N=50010;
const int P=201314;
int n,m;
namespace SHU {
int head[N],nxt[N<<1],to[N<<1],lst=0;
inline void adde(int x,int y) {
nxt[++lst]=head[x]; to[lst]=y; head[x]=lst;
}
int fa[N],dep[N],sz[N],son[N],top[N],s_t[N],t_s[N],ind=0;
void dfs1(int u) {
sz[u]=1;
int pos=-1;
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
dep[v]=dep[u]+1;
dfs1(v);
sz[u]+=sz[v];
if(pos==-1 || sz[pos]<sz[v]) pos=v;
}
son[u]=pos;
}
void dfs2(int u) {
// printf("u=%d\n",u);
t_s[u]=++ind; s_t[ind]=u;
if(son[u]!=-1) {
top[son[u]]=top[u];
dfs2(son[u]);
}
for(int i=head[u];i;i=nxt[i])
if(to[i]!=son[u]) {
int v=to[i];
top[v]=v;
dfs2(v);
}
}
inline void Init() {
fa[1]=0; dep[0]=0;
dep[1]=1; top[1]=1;
dfs1(1); dfs2(1);
}
#define lc (u<<1)
#define rc (lc|1)
#define left lc,l,mid
#define right rc,mid+1,r
#define mid ((l+r)>>1)
#define root 1,1,n
const int ALL=N<<2;
int val[ALL],laz[ALL];
inline void Update(int u,int l,int r,int v) {
(laz[u]+=v)%=P; (val[u]+=v*(r-l+1)%P)%=P;
}
inline void Push_Dn(int u,int l,int r) {
if(laz[u]) {
Update(left,laz[u]);
Update(right,laz[u]);
laz[u]=0;
}
}
void modify(int u,int l,int r,int L,int R,int v) {
// assert(L<=R);
// printf("%d %d %d %d %d %d\n",u,l,r,L,R,v);
if(L<=l && r<=R) {
Update(u,l,r,v); return;
}
Push_Dn(u,l,r);
if(L<=mid) modify(left,L,R,v);
if(R> mid) modify(right,L,R,v);
val[u]=(val[lc]+val[rc])%P;
}
int query(int u,int l,int r,int L,int R) {
if(L<=l && r<=R) return val[u];
Push_Dn(u,l,r);
int ret=0;
if(L<=mid) ret+=query(left,L,R);
if(R> mid) ret+=query(right,L,R);
return ret%P;
}
inline void Modify(int u) {
while(dep[top[u]]!=0) {
// printf("Modify::%d %d\n",u,top[u]);
modify(root,t_s[top[u]],t_s[u],1);
u=fa[top[u]];
}
// printf("val=%d\n",val[1]);
}
inline int Query(int u) {
int ret=0;
while(dep[top[u]]!=0) {
ret=(ret+query(root,t_s[top[u]],t_s[u]))%P;;
// printf("%d %d %d\n",u,top[u],ret);
u=fa[top[u]];
}
return ret;
}
}
struct QUERY {
int l,r,p,ans;
inline void in() {
read(l); read(r); read(p); ++l; ++r; ++p;
}
}a[N];
struct STA {
int p,u,id,type;
bool operator < (const STA &a)const {
return p<a.p || (p==a.p && u<a.u);
}
}q[N<<1]; int ind=0;
signed main() {
// freopen("3.in","r",stdin);
// freopen("my.out","w",stdout);
read(n); read(m);
for(int i=2;i<=n;i++) {
read(SHU::fa[i]); ++SHU::fa[i];
SHU::adde(SHU::fa[i],i);
}
SHU::Init();
for(int i=1;i<=m;i++) {
a[i].in();
q[++ind]=(STA) {a[i].l-1,a[i].p,i,-1};
q[++ind]=(STA) {a[i].r ,a[i].p,i, 1};
}
sort(q+1,q+ind+1);
int cur=1;
while(q[cur].p==0 && cur<=ind) ++cur;
for(int i=1;i<=n;i++) {
// printf("i=%d\n",i);
SHU::Modify(i);
while(q[cur].p==i && cur<=ind) {
(a[q[cur].id].ans+=q[cur].type*SHU::Query(q[cur].u))%=P;
// printf("%d\n",a[q[cur].id].ans);
++cur;
}
}
for(int i=1;i<=m;i++) {
printf("%d\n",(a[i].ans+P)%P);
}
return 0;
}
用时:1h