[LNOI2014]LCA

考虑到\(dep\)等同于到根的点数。
考虑把\([l,r]\)的点到根节点都打上1的标记,再查询\(z\)到根的权值即可。
考虑如何不重的统计。
那么就进行前缀和,并且从小到大加入,然后拆开一个询问的操作就可以。

树剖加线段树,\(O(nlog^2n)\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 500005
#define mod 201314

ll n,m;

ll cnt,head[N];

struct P{
	int to,next;
}e[N << 2];

inline void add(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}

ll son[N],siz[N],fa[N],dep[N],top[N],dfn[N];

inline void dfs(int u,int f){
	dep[u] = dep[f] + 1;
	fa[u] = f;
	siz[u] = 1;
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == f)
		continue;
		dfs(v,u);
		siz[u] += siz[v];
		if(siz[v] > siz[son[u]])
		son[u] = v;
	}
}

ll dfncnt;

inline void dfs2(int u,int t){
	top[u] = t;
	dfn[u] = ++dfncnt;
	if(son[u])dfs2(son[u],t);
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == fa[u] || v == son[u] || v == 1)
		continue;
		dfs2(v,v);
	}
}

//tree_cut__________

ll s[N << 2],tag[N << 2];

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

inline void up(int u){
	s[u] = (s[ls(u)] + s[rs(u)]) % mod;
}

inline void down(int u,int l,int r){
	if(tag[u]){
		tag[ls(u)] += tag[u];
		s[ls(u)] += tag[u] * (mid - l + 1);	
		s[ls(u)] %= mod;	
		tag[rs(u)] += tag[u];
		s[rs(u)] += tag[u] * (r - mid);	
		s[rs(u)] %= mod;						
		tag[u] = 0;
 	}
}

inline void change(int u,int l,int r,int tl,int tr,int p){
//	std::cout<<u<<" "<<l<<" "<<r<<" "<<tl<<" "<<tr<<" "<<p<<std::endl;
	if(tl <= l && r <= tr){
		tag[u] += p;
		s[u] += p * (r - l + 1);
		s[u] %= mod;			
		return ;
	}
	down(u,l,r);
	if(tl <= mid)
	change(ls(u),l,mid,tl,tr,p);
	if(tr > mid)
	change(rs(u),mid + 1,r,tl,tr,p);
	up(u);
}

inline ll qi(int u,int l,int r,int tl,int tr){
	ll ans = 0;
//	std::cout<<l<<" "<<r<<" "<<tl<<" "<<tr<<" "<<s[u]<<std::endl;
	if(tl <= l && r <= tr)
	return s[u];
	down(u,l,r);
	if(tl <= mid)
	ans += qi(ls(u),l,mid,tl,tr),ans %= mod;
	if(tr > mid)
	ans += qi(rs(u),mid + 1,r,tl,tr),ans %= mod;
	return ans;
}


//______________________

ll qcnt;

struct d{
	ll in,opt,id;
}q[N];

bool operator < (d a,d b){
	return a.in < b.in;
}

ll final[N],ans[N];

ll tp;

inline void add(int x){
//	std::cout<<"add"<<x<<":"<<std::endl;
	while(dfn[top[x]] != dfn[1]){
		change(1,1,n,dfn[top[x]],dfn[x],1);
//		std::cout<<dfn[top[x]]<<" "<<dfn[x]<<std::endl;		
		x = fa[top[x]];
	}
	change(1,1,n,dfn[1],dfn[x],1);
//	std::cout<<dfn[1]<<" "<<dfn[x]<<std::endl;
}

inline void deal(int p){
//	std::cout<<"deal"<<p<<":"<<std::endl;
	int x = final[q[p].id];
	ll f = 0;
	while(dfn[top[x]] != dfn[1]){
		f += qi(1,1,n,dfn[top[x]],dfn[x]);
//		std::cout<<dfn[top[x]]<<" "<<dfn[x]<<" "<<f<<std::endl;
		x = fa[top[x]];
	}
	f += qi(1,1,n,dfn[1],dfn[x]);
//	std::cout<<dfn[1]<<" "<<dfn[x]<<" "<<f<<std::endl;
	ans[q[p].id] = (ans[q[p].id] + q[p].opt * f + mod) % mod;
}

int main(){
	scanf("%lld%lld",&n,&m);
	for(int i = 2;i <= n;++i){
		ll x;
		scanf("%lld",&x);
		x ++ ;
		add(i,x);
		add(x,i);
	}
	dfs(1,0);
	dfs2(1,1);
//	for(int i = 1;i <= n;++i){
//		std::cout<<dfn[i]<<" "<<son[i]<<std::endl;
//	}
	for(int i = 1;i <= m;++i){
		ll l,r,z;
		scanf("%lld%lld%lld",&l,&r,&z);
		l ++ ;
		r ++ ;
		z ++ ;
		l -- ;
		q[++qcnt].id = i;
		q[qcnt].in = l;
		q[qcnt].opt = -1;
		q[++qcnt].id = i;
		q[qcnt].in = r;
		q[qcnt].opt = 1;
		final[i] = z;
	}
	std::sort(q + 1,q + qcnt + 1);
//	for(int i = 1;i <= qcnt;++i){
//		std::cout<<q[i].in<<" "<<q[i].id<<" "<<q[i].opt<<std::endl;
//	}
	tp = 1;
	while(q[tp].in == 0){
		deal(tp);
		tp ++ ;
	}
	for(int i = 1;i <= n;++i){
		add(i);
		while(q[tp].in == i){
			deal(tp);
			tp ++ ;
		}
	}
	for(int i = 1;i <= m;++i)
	std::cout<<ans[i]<<std::endl;
}
posted @ 2021-08-02 17:10  fhq_treap  阅读(35)  评论(0编辑  收藏  举报