[LNOI 2014] LCA

题目传送-Luogu4211

题目传送-BZOJ3626

题意:

给你一棵\(n\)个节点的树,定义一个点的深度为它到1号节点的距离+1
\(q\)次询问,每次给出\((l,r,p)\),求\(\sum_{i=l}^rdep(LCA(i,p))\)

题解:

考虑计算LCA(x,y),我们把x->1经过的节点权值+1,那么答案就是y->1经过的权值和,这东西可以前缀一下,然后答案就是\(sum_r-sum_{l-1}\)
这个可以用离线+树剖搞出来

过程:

树剖写错了O(1)次
还忘了取模。。

代码:

const int N=50010;
const int P=201314;
int n,m;
namespace SHU {
	int head[N],nxt[N<<1],to[N<<1],lst=0;
	inline void adde(int x,int y) {
		nxt[++lst]=head[x]; to[lst]=y; head[x]=lst;
	}
	int fa[N],dep[N],sz[N],son[N],top[N],s_t[N],t_s[N],ind=0;
	void dfs1(int u) {
		sz[u]=1;
		int pos=-1;
		for(int i=head[u];i;i=nxt[i]) {
			int v=to[i];
			dep[v]=dep[u]+1;
			dfs1(v);
			sz[u]+=sz[v];
			if(pos==-1 || sz[pos]<sz[v]) pos=v;
		}
		son[u]=pos;
	}
	void dfs2(int u) {
		// printf("u=%d\n",u);
		t_s[u]=++ind; s_t[ind]=u;
		if(son[u]!=-1) {
			top[son[u]]=top[u];
			dfs2(son[u]);
		}
		for(int i=head[u];i;i=nxt[i])
			if(to[i]!=son[u]) {
				int v=to[i];
				top[v]=v;
				dfs2(v);
			}
	}
	inline void Init() {
		fa[1]=0; dep[0]=0;
		dep[1]=1; top[1]=1;
		dfs1(1); dfs2(1);
	}
	#define lc (u<<1)
	#define rc (lc|1)
	#define left lc,l,mid
	#define right rc,mid+1,r
	#define mid ((l+r)>>1)
	#define root 1,1,n
	const int ALL=N<<2;
	int val[ALL],laz[ALL];
	inline void Update(int u,int l,int r,int v) {
		(laz[u]+=v)%=P; (val[u]+=v*(r-l+1)%P)%=P;
	}
	inline void Push_Dn(int u,int l,int r) {
		if(laz[u]) {
			Update(left,laz[u]);
			Update(right,laz[u]);
			laz[u]=0;
		}
	}
	void modify(int u,int l,int r,int L,int R,int v) {
	// 	assert(L<=R);
	// 	printf("%d %d %d %d %d %d\n",u,l,r,L,R,v);
		if(L<=l && r<=R) {
			Update(u,l,r,v); return;
		}
		Push_Dn(u,l,r);
		if(L<=mid) modify(left,L,R,v);
		if(R> mid) modify(right,L,R,v);
		val[u]=(val[lc]+val[rc])%P;
	}
	int query(int u,int l,int r,int L,int R) {
		if(L<=l && r<=R) return val[u];
		Push_Dn(u,l,r);
		int ret=0;
		if(L<=mid) ret+=query(left,L,R);
		if(R> mid) ret+=query(right,L,R);
		return ret%P;
	}
	inline void Modify(int u) {
		while(dep[top[u]]!=0) {
			// printf("Modify::%d %d\n",u,top[u]);
			modify(root,t_s[top[u]],t_s[u],1);
			u=fa[top[u]];
		}
		// printf("val=%d\n",val[1]);
	}
	inline int Query(int u) {
		int ret=0;
		while(dep[top[u]]!=0) {
			ret=(ret+query(root,t_s[top[u]],t_s[u]))%P;;
			// printf("%d %d %d\n",u,top[u],ret);
			u=fa[top[u]];
		}
		return ret;
	}
}
struct QUERY {
	int l,r,p,ans;
	inline void in() {
		read(l); read(r); read(p); ++l; ++r; ++p;
	}
}a[N];
struct STA {
	int p,u,id,type;
	bool operator < (const STA &a)const {
		return p<a.p || (p==a.p && u<a.u);
	}
}q[N<<1]; int ind=0;
signed main() {
	// freopen("3.in","r",stdin);
	// freopen("my.out","w",stdout);
	read(n); read(m);
	for(int i=2;i<=n;i++) {
		read(SHU::fa[i]); ++SHU::fa[i];
		SHU::adde(SHU::fa[i],i);
	}
	SHU::Init();
	for(int i=1;i<=m;i++) {
		a[i].in();
		q[++ind]=(STA) {a[i].l-1,a[i].p,i,-1};
		q[++ind]=(STA) {a[i].r  ,a[i].p,i, 1};
	}
	sort(q+1,q+ind+1);
	int cur=1;
	while(q[cur].p==0 && cur<=ind) ++cur;
	for(int i=1;i<=n;i++) {
		// printf("i=%d\n",i);
		SHU::Modify(i);
		while(q[cur].p==i && cur<=ind) {
			(a[q[cur].id].ans+=q[cur].type*SHU::Query(q[cur].u))%=P;
			// printf("%d\n",a[q[cur].id].ans);
			++cur;
		}
	}
	for(int i=1;i<=m;i++) {
		printf("%d\n",(a[i].ans+P)%P);
	}
	return 0;
}

用时:1h

posted @ 2018-08-28 10:57  functionendless  阅读(155)  评论(0编辑  收藏  举报