[bzoj3626] [LNOI2014]LCA

Description

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求\(\sum_{l \leq i \leq r}dep[LCA(i,z)]\)

Input

第一行2个整数n q。 接下来n-1行,分别表示点1到点n-1的父节点编号。 接下来q行,每行3个整数l r z。

Output

输出q行,每行表示一个询问的答案。每个答案对201314取模输出

Sample Input

5 2
0
0
1
1
1 4 3
1 4 2

Sample Output

8
5

Solution

在线看起来就一脸不可做的样子,考虑离线怎么做。

考虑一个转化:先给每个点定个权值,初始为0,那么\(dep[lca(x,y)]\)可以转化成先把\(1\to x\)这条链每个点加上\(1\),然后求\(1 \to y\)这条链的点权之和。

然后考虑\(\sum_{i=l}^r dep[lca]=\sum_{i=1}^rdep[lca]-\sum_{i=1}^{l-1}dep[lca]\),可以得到做法:

先把一个询问拆成两个,然后按\(r\)为关键字\(sort\)一遍,然后从1到\(n\)枚举,链上加1,当枚举到\(r\)的时候,处理下所有终点为\(r\)的询问就好了。

链上操作用树链剖分维护就好了,代码很好写。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
int read() {int x;read(x);return x;}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;
const int mod = 201314;

int n,m,top,dfn[maxn];
struct node{
	int r,z,op,ans,id;
	bool operator < (const node &rhs) const {return r<rhs.r;}
}in[maxn];

#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)

struct Segment_Tree {
	int tr[maxn<<2],tag[maxn<<2];
	void update(int p) {tr[p]=tr[ls]+tr[rs];}
	void push_tag(int p,int l,int r,int v) {tr[p]=(tr[p]+1ll*(r-l+1)*v)%mod,tag[p]=(tag[p]+v)%mod;}
	void pushdown(int p,int l,int r) {
		if(!tag[p]) return ;
		push_tag(ls,l,mid,tag[p]),push_tag(rs,mid+1,r,tag[p]);
		tag[p]=0;
	}
	void modify(int p,int l,int r,int x,int y) {
		if(x<=l&&r<=y) return push_tag(p,l,r,1),void();
		pushdown(p,l,r);
		if(x<=mid) modify(ls,l,mid,x,y);
		if(y>mid) modify(rs,mid+1,r,x,y);
		update(p);
	}
	int query(int p,int l,int r,int x,int y) {
		if(x<=l&&r<=y) return tr[p];
		pushdown(p,l,r);int ans=0;
		if(x<=mid) ans=(ans+query(ls,l,mid,x,y))%mod;
		if(y>mid) ans=(ans+query(rs,mid+1,r,x,y))%mod;
		return ans;
	}
}SGT;

#undef ls
#undef rs
#undef mid

struct Heavy_Light_Decomposition {
	int head[maxn],sz[maxn],dfn_cnt,tot,dep[maxn],hs[maxn],fa[maxn],top[maxn];
	struct edge{int to,nxt;}e[maxn<<1];
	void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
	void ins(int u,int v) {add(u,v),add(v,u);}
	void dfs1(int x,int f) {
		fa[x]=f,sz[x]=1,dep[x]=dep[f]+1;
		for(int i=head[x];i;i=e[i].nxt)
			if(e[i].to!=f) {
				dfs1(e[i].to,x),sz[x]+=sz[e[i].to];
				if(sz[hs[x]]<sz[e[i].to]) hs[x]=e[i].to;
			}
	}
	void dfs2(int x) {
		dfn[x]=++dfn_cnt;
		if(hs[fa[x]]==x) top[x]=top[fa[x]];
		else top[x]=x;
		if(hs[x]) dfs2(hs[x]);
		for(int i=head[x];i;i=e[i].nxt)
			if(e[i].to!=hs[x]&&e[i].to!=fa[x]) dfs2(e[i].to);
	}
	void modify(int x) {
		while(x) {
			SGT.modify(1,1,n,dfn[top[x]],dfn[x]);
			x=fa[top[x]];
		}
	}
	int query(int x) {
		int ans=0;
		while(x) {
			ans=(ans+SGT.query(1,1,n,dfn[top[x]],dfn[x]))%mod;
			x=fa[top[x]];
		}
		return ans;
	}
}HLD;

int cmp(node a,node b) {return a.id<b.id;}

int main() {
	read(n),read(m);
	for(int i=2,x;i<=n;i++) read(x),x++,HLD.ins(x,i);
	for(int i=1;i<=m;i++) {
		read(in[i+m].r),in[i+m].op=-1;
		read(in[i].r),in[i].r++,in[i].op=1;
		read(in[i].z),in[i].z++,in[i+m].z=in[i].z;
		in[i].id=in[i+m].id=i;
	}
	sort(in+1,in+m*2+1);
	HLD.dfs1(1,0),HLD.dfs2(1);
	int p=1;
	while(p<=m*2&&in[p].r==0) p++;
	for(int i=1;i<=n;i++) {
		HLD.modify(i);
		while(p<=m*2&&in[p].r==i) in[p].ans=HLD.query(in[p].z)*in[p].op,p++;
	}
	sort(in+1,in+m*2+1,cmp);
	for(int i=1;i<=m;i++) 
		write(((in[i*2].ans+in[i*2-1].ans)%mod+mod)%mod);
	return 0;
}

posted @ 2018-12-26 19:23  Hyscere  阅读(111)  评论(0编辑  收藏  举报