P4211
[LNOI2014]LCA
还是有相当思维难度的一道好题。
不过没有暴力分,并不明白这个数据规模的分层是用来干什么的。
考虑一种简单的情况,
那么假如说我们将从
那么现在就好玩了,我们将
但问题是,我们如果暴力这样做,甚至不如倍增 LCA 快。
我们再挖掘一个性质,对于节点
那么这样,我们的离线就有了思路。
对于每个询问
修改路径权值和求路径权值是树链剖分的基本操作。
时间复杂度
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cstdlib>
#define ll long long
using namespace std;
const ll N=5e4,mo=201314;
ll n,m,tot,cnt,x;
ll head[N+5],ver[N*2+5],nxt[N*2+5];
ll hs[N+5],id[N+5],fa[N+5],dt[N+5],siz[N+5],top[N+5];
vector<ll> flgl[N+5],flgr[N+5];
struct node{
ll l,r,z,ans;
}q[N+5];
struct sgt{
ll l,r,dat,laz;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define dat(x) tree[x].dat
#define laz(x) tree[x].laz
}tree[N*4+5];
void build(ll p,ll l,ll r) {
l(p)=l;r(p)=r;
if(l==r) return;
ll mid=(l+r)>>1;
build(p*2,l,mid);build(p*2+1,mid+1,r);
}
void spread(ll p) {
if(laz(p)) {
dat(p*2)=(dat(p*2)+laz(p)*(r(p*2)-l(p*2)+1))%mo;
laz(p*2)=(laz(p*2)+laz(p))%mo;
dat(p*2+1)=(dat(p*2+1)+laz(p)*(r(p*2+1)-l(p*2+1)+1))%mo;
laz(p*2+1)=(laz(p*2+1)+laz(p))%mo;
laz(p)=0;
}
}
ll query(ll p,ll l,ll r) {
if(l<=l(p)&&r>=r(p)) return dat(p)%mo;
spread(p);
ll mid=(l(p)+r(p))>>1,res=0;
if(l<=mid) res+=query(p*2,l,r);
if(r>mid) res+=query(p*2+1,l,r);
return res%mo;
}
void chg(ll p,ll l,ll r) {
if(l<=l(p)&&r>=r(p)) {
laz(p)=(laz(p)+1)%mo;
dat(p)=(dat(p)+r(p)-l(p)+1)%mo;
return;
}
spread(p);
ll mid=(l(p)+r(p))>>1;
if(l<=mid) chg(p*2,l,r);
if(r>mid) chg(p*2+1,l,r);
dat(p)=(dat(p*2)+dat(p*2+1))%mo;
}
void dfs(ll p,ll fath) {
dt[p]=dt[fath]+1;fa[p]=fath;siz[p]=1;
ll ma=0;
for(ll i=head[p];i;i=nxt[i]) {
if(ver[i]==fath) continue;
dfs(ver[i],p);siz[p]+=siz[ver[i]];
if(siz[ver[i]]>ma) {
hs[p]=ver[i];ma=siz[ver[i]];
}
}
}
void _dfs(ll p,ll topf) {
id[p]=++cnt;top[p]=topf;
if(!hs[p]) return;
_dfs(hs[p],topf);
for(ll i=head[p];i;i=nxt[i]) {
if(ver[i]==fa[p]||ver[i]==hs[p]) continue;
_dfs(ver[i],ver[i]);
}
}
void chgpath(ll x,ll y) {
while(top[x]!=top[y]) {
if(dt[top[x]]<dt[top[y]]) swap(x,y);
chg(1,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dt[x]>dt[y]) swap(x,y);
chg(1,id[x],id[y]);
}
ll qpath(ll x,ll y) {
ll ans=0;
while(top[x]!=top[y]) {
if(dt[top[x]]<dt[top[y]]) swap(x,y);
ans=(ans+query(1,id[top[x]],id[x]))%mo;
x=fa[top[x]];
}
if(dt[x]>dt[y]) swap(x,y);
ans=(ans+query(1,id[x],id[y]))%mo;
return ans;
}
void add(ll u,ll v) {
ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;
}
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}
void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {
do{buf[++len]=x%10+48;x/=10;}while(x);
}
else {
putchar('-');
do{buf[++len]=-(x%10)+48;x/=10;}while(x);
}
while(len>=0) putchar(buf[len--]);
}
int main() {
n=read();m=read();
for(ll i=1;i<n;i++) {
x=read();add(x,i);add(i,x);
}
dfs(0,n);_dfs(0,0);
build(1,1,n);
for(ll i=1;i<=m;i++) {
q[i].l=read();q[i].r=read();q[i].z=read();
if(q[i].l>0) flgl[q[i].l-1].push_back(i);
flgr[q[i].r].push_back(i);
}
for(ll i=0;i<n;i++) {
chgpath(i,0);
for(ll j=0;j<flgl[i].size();j++) {
q[flgl[i][j]].ans=(q[flgl[i][j]].ans-qpath(q[flgl[i][j]].z,0)+mo)%mo;
}
for(ll j=0;j<flgr[i].size();j++) {
q[flgr[i][j]].ans=(q[flgr[i][j]].ans+qpath(q[flgr[i][j]].z,0))%mo;
}
}
for(ll i=1;i<=m;i++) {
write(q[i].ans);putchar('\n');
}
return 0;
}