给出一棵树,q次询问,每次询问
这道题在线明显不可做。(在线A了的大犇请收下我的膝盖)
首先,我们来思考一下,一组询问怎么做?
暴力的想法,我们把每要询问的点往上都打上标记,然后把z点往上找到每个标记第一次出现的位置。
其实我们可以发现,每个标记的深度等同于它上面有多少个和它一样的标记。
那么我们可以把每个点到根的路径都+1,然后询问z到根的和,就是答案了。
很显然可以用链剖搞。(两个log不优美?原谅本蒟蒻不会打LCT)
那么多组询问呢?
本来我是想到用莫队算法的,但是复杂度过于爆炸,多出来的根号n实在碍眼。
换种思路,区间[l,r]的答案=区间[1,r]的答案-区间[1,l-1]的答案。
那么我们把每个询问拆成两个,一个+,一个-。
把询问按端点排序,依次往后推,就可以满足线性了。
Orz 全民偶像hzwer
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define N 50005
using namespace std;
const int mo=201314;
struct note{int p,z,id,bz;}ask[N*2];
int t[N],next[N],last[N],size[N],son[N],w[N],top[N],fa[N];
int n,m,tot,l,r,tr[N*3],add[N*3],an[N*2];
bool cmp(note x,note y) {return x.p<y.p;}
void ins(int x,int y) {
t[++l]=y;next[l]=last[x];last[x]=l;
}
void dfs(int x) {
size[x]=1;int k=0;
rep(i,x) {
dfs(t[i]);size[x]+=size[t[i]];
if (size[t[i]]>k) k=size[t[i]],son[x]=t[i];
}
}
void make(int x,int y) {
w[x]=++tot;top[x]=y;
if (!son[x]) return;
make(son[x],y);
rep(i,x) if (t[i]!=son[x]) make(t[i],t[i]);
}
void back(int v,int x,int len) {
(tr[v]+=len*x)%=mo;add[v]+=x;
}
void down(int v,int l,int r) {
if (add[v]) {
int m=(l+r)/2;
back(v*2,add[v],m-l+1);
back(v*2+1,add[v],r-m);
add[v]=0;
}
}
void change(int v,int l,int r,int x,int y) {
if (l==x&&r==y) {back(v,1,r-l+1);return;}
int m=(l+r)/2;down(v,l,r);
if (y<=m) change(v*2,l,m,x,y);
else if (x>m) change(v*2+1,m+1,r,x,y);
else change(v*2,l,m,x,m),change(v*2+1,m+1,r,m+1,y);
(tr[v]=tr[v*2]+tr[v*2+1])%=mo;
}
int find(int v,int l,int r,int x,int y) {
if (l==x&&r==y) return tr[v];
int m=(l+r)/2;down(v,l,r);
if (y<=m) return find(v*2,l,m,x,y);
else if (x>m) return find(v*2+1,m+1,r,x,y);
else return find(v*2,l,m,x,m)+find(v*2+1,m+1,r,m+1,y);
}
void revise(int x) {
int f=top[x];
while (x) {
change(1,1,n,w[f],w[x]);
x=fa[f];f=top[x];
}
}
int query(int x) {
int f=top[x],ans=0;
while (x) {
(ans+=find(1,1,n,w[f],w[x]))%=mo;
x=fa[f];f=top[x];
}
return ans;
}
int main() {
scanf("%d%d",&n,&m);
fo(i,2,n) scanf("%d",&fa[i]),ins(++fa[i],i);
dfs(1);make(1,1);tot=0;
fo(i,1,m) {
scanf("%d%d%d",&l,&r,&ask[++tot].z);l++,r++,ask[tot].z++;
ask[tot].p=l-1;ask[tot].id=i;ask[tot].bz=-1;
ask[++tot].p=r;ask[tot].id=i;ask[tot].bz=1;ask[tot].z=ask[tot-1].z;
}
sort(ask+1,ask+tot+1,cmp);int j=0;while (!ask[j+1].p) j++;
fo(i,1,n) {
revise(i);
while (ask[j+1].p==i) j++,an[ask[j].id]+=query(ask[j].z)*ask[j].bz;
}
fo(i,1,m) printf("%d\n",(an[i]+mo)%mo);
}