复习物理时突然有了这个题的做法。
我也不知道为啥学物理会想到这个
一个不用转化、不用扫描线、不用$LCT$树剖的$chuan$新做法:直接分块!
每个块开个$vector$记录询问。
散块直接暴力。整块把该询问丢进$vector$里。
询问处理完后处理每个块:
记$l,r$为块的左右端点,对每个点$x$算出$\sum\limits_{i=l}^rdeep[lca(i,x)]$,最后把属于该块的每个询问点的贡献加进去即可。
$dfs$一遍树。考虑每个点为$lca$的贡献。记$siz(i)$为$i$子树中编号在$[l,r]$的点的个数。
点$i$会对其整棵子树有$deep(i)\times siz(i)$的贡献,然后对其每个儿子$x$,要容斥减去$deep(i)\times siz(x)$的不合法贡献。
子树加,$dfs$序+差分即可。
空间$O(n\sqrt{n})$,用$O(1)LCA$的话时间为$O(n\sqrt{n})$。
用$Tarjan\ LCA$被卡空间了用树剖$LCA$被卡时间了被迫现学的$RMQ\ LCA$,做LCA题学LCA没毛病
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define maxn 50005
#define inf 0x3f3f3f3f
const int mod = 201314;
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
int siz[maxn],h[maxn],seg[maxn],pos[maxn],low[maxn],deep[maxn]={inf,1},num,cnt;
int be[maxn],a[maxn],ans[maxn],f[maxn<<1][22],fir[maxn],lg[maxn<<1],all;
struct edge{
int pre,to;
}e[maxn];
inline int cmp(int x,int y){return deep[x]<deep[y]?x:y;}
inline void add(int from,int to){
e[++num].pre=h[from],h[from]=num,e[num].to=to;
}
void dfs(int node=1){
f[fir[node]=++all][0]=pos[seg[node]=++cnt]=node;
int x;
for(register int i=h[node];i;i=e[i].pre){
x=e[i].to,deep[x]=deep[node]+1,dfs(x);
f[++all][0]=node;
}
low[node]=cnt;
}
void ST(){
for(register int i=2;i<=all;++i)lg[i]=lg[i>>1]+1;
for(register int j=1;j<=lg[all];++j)
for(register int i=1;i+(1<<(j-1))<=all;++i)
f[i][j]=cmp(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
inline int query(int l,int r){
if(l>r)swap(l,r);
int len=lg[r-l+1];
return cmp(f[l][len],f[r-(1<<len)+1][len]);
}
inline int lca(int x,int y){
return query(fir[x],fir[y]);
}
#define modify(x,d) a[seg[x]]+=d,a[low[x]+1]-=d
#define id(x) (x>=l&&x<=r)
struct BLOCK{
int l,r;
vector<pair<int,int> >q;
void calc(int node=1){
siz[node]=id(node);
int x;
for(register int i=h[node];i;i=e[i].pre){
x=e[i].to;
calc(x),siz[node]+=siz[x];
}
modify(node,deep[node]*siz[node]);
for(register int i=h[node];i;i=e[i].pre){
x=e[i].to;
modify(x,(-deep[node]*siz[x]));
}
}
void solve(){
calc();
for(register int i=1;i<=cnt;++i)a[i]+=a[i-1];
for(vector<pair<int,int> >::iterator iter=q.begin();iter!=q.end();++iter)
(ans[iter->second]+=a[iter->first])%=mod;
}
}b[250];
inline void odd(int l,int r,int x,int p){
for(register int i=l;i<=r;++i)ans[p]+=deep[lca(i,x)];
}
int main(){
int n=read(),m=read(),l,r,x,sq=sqrt(n),len=n/sq+bool(n%sq);
for(register int i=2;i<=n;++i)add(read()+1,i);
dfs(),ST();
for(register int i=1;i<=len;++i){
b[i].l=b[i-1].r+1,b[i].r=min(b[i].l+sq-1,n);
for(register int j=b[i].l;j<=b[i].r;++j)
be[j]=i;
}
for(register int i=1;i<=m;++i){
l=read()+1,r=read()+1,x=read()+1;
if(be[l]==be[r]){odd(l,r,x,i);}
else {
odd(l,b[be[l]].r,x,i);
odd(b[be[r]].l,r,x,i);
x=seg[x];
for(register int j=be[l]+1;j<be[r];++j)
b[j].q.push_back((pair<int,int>){x,i});
}
}
for(register int i=1;i<=len;++i)memset(a,0,sizeof a),b[i].solve();
for(register int i=1;i<=m;++i)printf("%d\n",(ans[i]%mod+mod)%mod);
}