樹剖+線段樹--bzoj3626
阿新 • • 發佈:2018-12-02
也是一道思路很好的題。
對於一個點
,和一個標號區間
,要求
如果純暴力的話是
的,甚至連第一個部分分都拿不到
但是 一定是 到 的鏈上的某一個點,如果把這些點權值都設成 ,那麼答案就是 的每個點到 的鏈上的點權和(有點差分的思想),求鏈上的點權和就可以用樹剖+線段樹來做,但這樣複雜度還是很高。然而這個問題是可以翻過來的,就是對於 的每個點,把他們到 的鏈上的點權都 ,則答案就是 到 的這條鏈的點權和。
那就可以把詢問離線下來,把 變成 ,點的編號從小到大加進去,然後再處理這個地方的詢問就好了
程式碼如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 50005
#define ls cur<<1
#define rs cur<<1|1
#define len(x) (node[x].r-node[x].l+1)
using namespace std;
const int mod=201314;
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
int n,m,cnt,head[N],tot;
int siz[N],dep[N],dfn[N],rk[N],son[N],top[N],fa[N],num;
struct EDGE{
int to,nxt;
}edge[N<<1];
inline void add(int x,int y){
edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt;
}
void dfs1(int u,int fat){
siz[u]=1; int maxson=-1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to; if(v==fat) continue;
dep[v]=dep[u]+1; fa[v]=u;
dfs1(v,u); siz[u]+=siz[v];
if(siz[v]>maxson) maxson=siz[v],son[u]=v;
} return;
}
void dfs2(int u,int t){
top[u]=t; dfn[u]=++num; rk[num]=u;
if(!son[u]) return;
dfs2(son[u],t);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(!dfn[v]) dfs2(v,v);
}
}
struct Node{
int l,r,sum,lazy;
}node[N<<2];
inline void pushup(int cur){
node[cur].sum=node[ls].sum+node[rs].sum;
}
inline void pushdown(int cur){
if(node[cur].lazy){
int t=node[cur].lazy; node[cur].lazy=0;
node[ls].sum+=len(ls)*t; node[ls].lazy+=t;
node[rs].sum+=len(rs)*t; node[rs].lazy+=t;
}
}
void build(int cur,int L,int R){
if(L==R){
node[cur].l=node[cur].r=L; return;
}
int mid=(L+R)>>1;
build(ls,L,mid); build(rs,mid+1,R);
node[cur].l=node[ls].l,node[cur].r=node[rs].r;
pushup(cur); return;
}
void update(int cur,int L,int R){
if(L<=node[cur].l && node[cur].r<=R){
node[cur].sum+=len(cur); node[cur].lazy++;
return;
}
pushdown(cur);
int mid=(node[cur].l+node[cur].r)>>1;
if(L<=mid) update(ls,L,R);
if(mid<R) update(rs,L,R);
pushup(cur);
}
int query(int cur,int L,int R){
if(L<=node[cur].l && node[cur].r<=R) return node[cur].sum;
pushdown(cur);
int mid=(node[cur].l+node[cur].r)>>1,res=0;
if(L<=mid) (res+=query(ls,L,R))%=mod;
if(mid<R) (res+=query(rs,L,R))%=mod;
return res;
}
inline void change(int x,int y){
while(top[x]!=top[y]){
update(1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
update(1,dfn[y],dfn[x]);
}
inline int ask(int x){
int ans=0;
while(top[x]!=1){
ans+=query(1,dfn[top[x]],dfn[x]); ans%=mod;
x=fa[top[x]];
}
ans+=query(1,dfn[1],dfn[x]); ans%=mod;
return ans;
}
struct qwq{
int id,pos; bool flg;
bool operator <(const qwq &x) const{
return pos<x.pos;
}
}a[N<<1];
struct QUE{int z,ans;}q[N];
int main(){
n=rd(); m=rd();
for(int i=1;i<n;i++){
int x=rd(); ++x;
add(x,i+1);
}
dfs1(1,1); dfs2(1,1); build(1,1,n);
for(int i=1;i<=m;i++){
int l=rd(),r=rd();q[i].z=rd()+1; ++l,++r;
a[++tot].id=i,a[tot].pos=l-1,a[tot].flg=0;
a[++tot].id=i,a[tot].pos=r, a[tot].flg=1;
}
sort(a+1,a+tot+1); int now=0;
for(int i=1;i<=tot;i++){
while(now<a[i].pos){
++now; change(now,1);
}
if(!a[i].flg) q[a[i].id].ans-=ask(q[a[i].id].z);
else q[a[i].id].ans+=ask(q[a[i].id].z);
}
for(int i=1;i<=m;i++) printf("%d\n",(q[i].ans+mod)%mod);
return 0;
}