[LNOI2014]LCA
这道题难道不是数据结构水题吗 逃)
首先想到一个i点的\(dep\)相当于根节点走到i 进过的点之和,所以这个点对答案的贡献就是从这个点走到根节点。因此我们可以转换为当前节点\(i\)到根节点所经过的所有节点权值++。
显然可以用线段树+树链剖分的数据结构进行优化 对于每一个询问 建一颗权值线段树 存储当前区间\(sum\),\(sum\)存储的就是\(sum\)
然后我们需要想到用 类似于前缀和的思想来进行优化
例如 \(l=2 ,r=4 ,z=4\) 我们可以用前缀和的思想进行优化 计算\(1到4\)的\(sum\)\(-1到1的sum\) 就可以得到答案了
想到了前缀和 想到了树剖+线段树 如果每一次查询 你都要新建两次树
那就会GG!
因此我们又想到了莫队的思想,将询问区间的\(l,r\)排序(因为询问区间为\(1到l\),\(1到r\),左区间都是一样的,所以我们可以将l,r一起排序),然后一个一个的加点 这样就可以不用每一次询问都新建一颗树了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int mod=201314,maxn=100010;
int n,q,tot,fa[maxn],cnt_q;
int first[maxn],nxt[maxn<<1],to[maxn<<1],dep[maxn<<1],cnt_id;
int id[maxn<<1],rk[maxn<<1],size[maxn<<1],son[maxn<<1],top[maxn<<1],now;
int tag[maxn<<1],sum[maxn<<1];
struct node{
int id,pos,z,flag;
inline bool operator <(const node &x)const{
return pos<x.pos || (x.pos==pos && id<x.id);
}
}ques[maxn<<4];
struct node1{
int ans1,ans2;
}ans[maxn<<2];
void dfs1(int x,int father){
size[x]=1;fa[x]=father;
for(int i=first[x];i;i=nxt[i]){
int y=to[i];if(y==father) continue;
dep[y]=dep[x]+1;
dfs1(y,x);size[x]+=size[y];
if(size[son[x]]<size[y])
son[x]=y;
}
}
void dfs2(int x,int topo){
id[x]=++cnt_id;rk[cnt_id]=x;top[x]=topo;
if(son[x]) dfs2(son[x],topo);
for(int i=first[x];i;i=nxt[i]){
int y=to[i];if(y==fa[y] || y==son[x]) continue;
dfs2(y,y);
}
}
void add(int x,int y){nxt[++tot]=first[x];first[x]=tot;to[tot]=y;}
void tagg(int node,int l,int r,int ta)
{
sum[node]=(sum[node]+(r-l+1)*ta)%mod;
if(l<r) tag[node]=(tag[node]+ta)%mod;
}
void push_down(int node,int l,int r){
if(l<r && tag[node]){
int mid=(l+r)>>1;
tagg(node<<1,l,mid,tag[node]);
tagg(node<<1|1,mid+1,r,tag[node]);
}
tag[node]=0;
}
void push_up(int node){sum[node]=(sum[node<<1]+sum[node<<1|1])%mod;}
void modify(int node,int l,int r,int ql,int qr){
if(qr<l || ql>r) return ;
if(ql<=l && r<=qr){
tagg(node,l,r,1);
return ;
}
push_down(node,l,r);
int mid=(l+r)>>1;
modify(node<<1,l,mid,ql,qr);modify(node<<1|1,mid+1,r,ql,qr);
push_up(node);
}
void line_modify(int x,int y){
int tx=top[x],ty=top[y];
while(tx!=ty){
if(dep[tx]<dep[ty]){
x^=y^=x^=y;tx^=ty^=tx^=ty;
}
modify(1,1,n,id[tx],id[x]);
x=fa[tx];tx=top[x];
}
if(dep[x]<dep[y])
x^=y^=x^=y;
modify(1,1,n,id[y],id[x]);
}
int query(int node,int l,int r,int ql,int qr){
if(ql<=l && r<=qr) return (sum[node]%mod);
push_down(node,l,r);
int mid=(l+r)>>1,anss=0;
if(ql<=mid) anss+=query(node<<1,l,mid,ql,qr);
if(mid<qr) anss+=query(node<<1|1,mid+1,r,ql,qr);
return anss%mod;
}
int line_query(int x,int y){
int tx=top[x],ty=top[y],anss=0;
while(tx!=ty){
if(dep[tx]<dep[ty]){
x^=y^=x^=y;tx^=ty^=tx^=ty;
}
anss+=query(1,1,n,id[tx],id[x]);
anss%=mod;
x=fa[tx];tx=top[x];
}
if(dep[x]<dep[y])
x^=y^=x^=y;
anss+=query(1,1,n,id[y],id[x]);
return anss%mod;
}
signed main(){
scanf("%lld %lld",&n,&q);
for(int i=2,x;i<=n;i++){
scanf("%lld",&x);add(++x,i);
}
dep[1]=1;
dfs1(1,0);dfs2(1,1);
for(int i=1,l,r,z;i<=q;i++){
scanf("%lld %lld %lld",&l,&r,&z);r++;z++;
ques[++cnt_q]=((node){i,l,z,0});ques[++cnt_q]=((node){i,r,z,1});
}
sort(ques+1,ques+1+cnt_q);now=0;
for(int i=1;i<=cnt_q;i++){
while(now<ques[i].pos)
line_modify(1,++now);
int num=ques[i].id;
if(ques[i].flag==1) ans[num].ans1=line_query(1,ques[i].z);
else ans[num].ans2 =line_query(1,ques[i].z);
}
for(int i=1;i<=q;i++)
printf("%lld\n",(ans[i].ans1-ans[i].ans2+mod)%mod);
return 0;
}