模板:题目链接
进阶:题目链接
给定一棵 n n n个点的树。 q q q次询问,每次询问给出三个值 l , r , z l,r,z l,r,z,要求出 ∑ i = l r d e p ( L C A ( i , z ) ) \sum_{i=l}^{r}dep(LCA(i,z)) ∑i=lrdep(LCA(i,z))。
( n < = 1 e 5 , q < = 1 e 5 ) (n<=1e5,q<=1e5) (n<=1e5,q<=1e5)
考虑求点 a a a和点 b b b的 L C A LCA LCA深度,我们可以把点 a a a到 r o o t root root路径上的点权都加 1 1 1,然后查询点 b b b 到 r o o t root root的路径和就是他们的 L C A LCA LCA深度了。反过来修改 b b b到 r o o t root root的路径,查 a a a到 r o o t root root的路径和也是一样的。
那么考虑多个点和单个点的 L C A LCA LCA深度和,可以把每个点到 r o o t root root的路径都加上 1 1 1,然后查询单个点到 r o o t root root的路径和。
这样就变成了树链修改和查询的操作,就可以用树链剖分维护了。
但是这题不能每次询问都进行一次 o ( ( r − l ) l o g 2 n ) o((r-l)log^2n) o((r−l)log2n)的修改,所以要离线求前缀和,再拿前缀和减一下就行了。总的复杂度 o ( ( n + q ) l o g 2 n ) o((n+q)log^{2}n) o((n+q)log2n)。
#include
using namespace std;
typedef long long ll;
const ll mod=201314;
typedef pair<ll,ll> P;
ll tree[1000005],laz[1000005];
void push_down(ll k,ll l,ll r)
{
ll mid=(l+r)/2;
tree[2*k+1]+=laz[k]*(mid-l+1);
laz[2*k+1]+=laz[k];
tree[2*k+2]+=laz[k]*(r-mid);
laz[2*k+2]+=laz[k];
laz[k]=0;
}
ll query(ll k,ll l,ll r,ll x,ll y)
{
if(x<=l&&r<=y)
{
return tree[k];
}
push_down(k,l,r);
ll ans=0,mid=(l+r)/2;
if(x<=mid)ans+=query(2*k+1,l,mid,x,y);
if(y>=mid+1)ans+=query(2*k+2,mid+1,r,x,y);
return ans;
}
void update(ll k,ll l,ll r,ll x,ll y,ll a)
{
if(x<=l&&r<=y)
{
tree[k]+=a*(r-l+1);
laz[k]+=a;
return ;
}
push_down(k,l,r);
ll mid=(l+r)/2;
if(x<=mid)update(2*k+1,l,mid,x,y,a);
if(y>=mid+1)update(2*k+2,mid+1,r,x,y,a);
tree[k]=tree[2*k+1]+tree[2*k+2];
}
vector<ll>v[100005];
ll dep[100005],fa[100005],siz[100005],son[100005];
void dfs1(ll x,ll pre)
{
siz[x]=1;
dep[x]=dep[pre]+1;
fa[x]=pre;
for(ll i=0;i<v[x].size();i++)
{
ll to=v[x][i];
if(to!=pre)
{
dfs1(to,x);
siz[x]+=siz[to];
}
}
son[x]=x;
for(ll i=0;i<v[x].size();i++)
{
ll to=v[x][i];
if(to!=pre)
{
if(son[x]==x||siz[son[x]]<siz[to])son[x]=to;
}
}
}
ll id[100005],idx,top[100005];
void dfs2(ll x,ll pre)
{
if(son[pre]==x)top[x]=top[pre];
else top[x]=x;
id[x]=++idx;
if(son[x]!=x)dfs2(son[x],x);
for(ll i=0;i<v[x].size();i++)
{
ll to=v[x][i];
if(to!=pre&&to!=son[x])
{
dfs2(to,x);
}
}
}
ll n,m;
void add(ll x,ll val)
{
while(top[x]!=1)
{
update(1,1,n,id[top[x]],id[x],val);
x=fa[top[x]];
}
update(1,1,n,id[top[x]],id[x],val);
}
ll get(ll x)
{
if(x==0)return 0;
ll ans=0;
while(top[x]!=1)
{
ans+=query(1,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
ans+=query(1,1,n,id[top[x]],id[x]);
return ans;
}
map<ll,ll>mp[100005];
vector<P>ve;
struct Q
{
ll l,r,z;
}q[200005];
int main()
{
scanf("%lld%lld",&n,&m);
for(ll i=2;i<=n;i++)
{
ll a;
scanf("%lld",&a);
a++;
v[a].push_back(i);
v[i].push_back(a);
}
dfs1(1,0);
dfs2(1,0);
for(int i=1;i<=m;i++)
{
ll l,r,z;
scanf("%lld%lld%lld",&l,&r,&z);
l++;r++;z++;
q[i]=Q{l,r,z};
ve.push_back(P(l-1,z));
ve.push_back(P(r,z));
}
sort(ve.begin(),ve.end());
int cnt=1;
for(int i=0;i<ve.size();i++)
{
while(cnt<=n&&cnt<=ve[i].first)
{
add(cnt,1);
cnt++;
}
mp[ve[i].first][ve[i].second]=get(ve[i].second)%mod;
}
for(int i=1;i<=m;i++)
{
ll l=q[i].l,r=q[i].r,z=q[i].z;
ll ans=mp[r][z]-mp[l-1][z];
printf("%lld\n",(ans%mod+mod)%mod);
}
return 0;
}