1. 程式人生 > 實用技巧 >題解 P6453 【[LNOI2014]LCA】

題解 P6453 【[LNOI2014]LCA】

題目連結

Solution [LNOI2014]LCA

題目大意:給定一棵樹,每次給定 \(l,r,z\),詢問 \(\sum_{i=l}^{r}dep[LCA(i,z)]\)

樹鏈剖分


分析:

關鍵性質在於,從根到兩個點的路徑的交,等於從根到它們的 \(LCA\) 的路徑。而一個點的深度,就相當於根到那個點的路徑長度。

因此原問題等價於每次對於 \(x \in [l,r]\),將根到 \(x\) 的路徑加 \(1\),然後詢問根到 \(z\) 的路徑上的權值之和。

這個可以離線下來,變成將 \(x \in [1,k]\) 的路徑加 \(1\),做個差分就可以了。

直接樹剖加上線段樹維護。

#include <cstdio>
#include <cctype>
#include <vector>
#pragma GCC optmize(2)
using namespace std;
typedef long long ll;
constexpr int maxn = 5e4 + 100,inf = 0x7fffffff,mod = 201314;
inline int add(const int a,const int b){return (a + b) % mod;}
inline int sub(const int a,const int b){return (a - b + mod) % mod;}
inline int mul(const int a,const int b){return (1ll * a * b) % mod;}
struct IO{//-std=c++11,with cstdio and cctype
	private:
		static constexpr int ibufsiz = 1 << 20;
		char ibuf[ibufsiz + 1],*inow = ibuf,*ied = ibuf;
		static constexpr int obufsiz = 1 << 20;
		char obuf[obufsiz + 1],*onow = obuf;
		const char *oed = obuf + obufsiz;
	public:
		inline char getchar(){
			#ifndef ONLINE_JUDGE
				return ::getchar();
			#else
				if(inow == ied){
					ied = ibuf + sizeof(char) * fread(ibuf,sizeof(char),ibufsiz,stdin);
					*ied = '\0';
					inow = ibuf;
				}
				return *inow++;
			#endif
		}
		template<typename T>
		inline void read(T &x){
			static bool flg;flg = 0;
			x = 0;char c = getchar();
			while(!isdigit(c))flg = c == '-' ? 1 : flg,c = getchar();
			while(isdigit(c))x = x * 10 + c - '0',c = getchar();
			if(flg)x = -x;
		}
		template <typename T,typename ...Y>
		inline void read(T &x,Y&... X){read(x);read(X...);}
		inline int readi(){static int res;read(res);return res;}
		inline long long readll(){static long long res;read(res);return res;}
		
		inline void flush(){
			fwrite(obuf,sizeof(char),onow - obuf,stdout);
			fflush(stdout);
			onow = obuf;
		}
		inline void putchar(char c){
			#ifndef ONLINE_JUDGE
				::putchar(c);
			#else
				*onow++ = c;
				if(onow == oed){
					fwrite(obuf,sizeof(char),obufsiz,stdout);
					onow = obuf;
				}
			#endif
		}
		template <typename T>
		inline void write(T x,char split = '\0'){
			static unsigned char buf[64];
			if(x < 0)putchar('-'),x = -x;
			int p = 0;
			do{
				buf[++p] = x % 10;
				x /= 10;
			}while(x);
			for(int i = p;i >= 1;i--)putchar(buf[i] + '0');
			if(split != '\0')putchar(split);
		}
		inline void lf(){putchar('\n');}
		~IO(){
			fwrite(obuf,sizeof(char),onow - obuf,stdout);
		}
}io;
template <typename A,typename B>
inline void chkmin(A &x,const B &y){if(y < x)x = y;}
template <typename A,typename B>
inline void chkmax(A &x,const B &y){if(y > x)x = y;}

int n,q,ans[maxn];
namespace st{
	#define ls (rt << 1)
	#define rs (rt << 1 | 1)
	struct node{
		int sum,add;
	}tr[maxn << 2];
	inline int calc(const int l,const int r){return r - l + 1;}
	inline void pushup(const int rt){tr[rt].sum = add(tr[ls].sum,tr[rs].sum);}
	inline void pushdown(const int rt,const int l,const int r){
		tr[ls].add = add(tr[ls].add,tr[rt].add);
		tr[rs].add = add(tr[rs].add,tr[rt].add);
		int mid = (l + r) >> 1;
		tr[ls].sum = add(tr[ls].sum,mul(calc(l,mid),tr[rt].add));
		tr[rs].sum = add(tr[rs].sum,mul(calc(mid + 1,r),tr[rt].add));
		tr[rt].add = 0;
	}
	inline void modify(const int a,const int b,const int v,const int l = 1,const int r = n,const int rt = 1){
		if(a <= l && b >= r){
			tr[rt].add = add(tr[rt].add,v);
			tr[rt].sum = add(tr[rt].sum,mul(calc(l,r),v));
			return;
		}
		pushdown(rt,l,r);
		const int mid = (l + r) >> 1;
		if(a <= mid)modify(a,b,v,l,mid,ls);
		if(b >= mid + 1)modify(a,b,v,mid + 1,r,rs);
		pushup(rt);
	}
	inline int query(const int a,const int b,const int l = 1,const int r = n,const int rt = 1){
		if(a <= l && b >= r)return tr[rt].sum;
		pushdown(rt,l,r);
		int mid = (l + r) >> 1,res = 0;
		if(a <= mid)res += query(a,b,l,mid,ls);
		if(b >= mid + 1)res += query(a,b,mid + 1,r,rs);
		return res % mod;
	}
	#undef ls
	#undef rs
}

namespace tree{
	vector<int> G[maxn];
	inline void addedge(int u,int v){
		// io.write(u,' '),io.write(v,'\n');
		G[u].push_back(v);}
	int dfs_tot,dfn[maxn],rnk[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn],faz[maxn];
	inline void dfs1(const int u){
		siz[u] = 1;
		for(int v : G[u]){
			dep[v] = dep[u] + 1;
			dfs1(v);
			siz[u] += siz[v];
			if(siz[v] > siz[son[u]])son[u] = v;
		}
	}
	inline void dfs2(const int u,const int tp){
		dfn[u] = ++dfs_tot;
		rnk[dfs_tot] = u;
		top[u] = tp;
		if(son[u])dfs2(son[u],tp);
		for(int v : G[u]){
			if(v == son[u])continue;
			dfs2(v,v);
		}
	}
	inline void modify(int u,const int v){
		while(u){
			st::modify(dfn[top[u]],dfn[u],v);
			u = faz[top[u]];
		}
	}
	inline int query(int u){
		int res = 0;
		while(u){
			res = add(res,st::query(dfn[top[u]],dfn[u]));
			u = faz[top[u]];
		}
		return res;
	}
}
struct oper{
	int id,z,flg;
};
vector<oper> vec[maxn];
int main(){
#ifndef ONLINE_JUDGE
	freopen("fafa.in","r",stdin);
#endif
	tree::dep[1] = 1;
	io.read(n,q);
	for(int i = 2;i <= n;i++)
		tree::faz[i] = io.readi() + 1,tree::addedge(tree::faz[i],i);
	tree::dfs1(1);
	tree::dfs2(1,1);
	for(int l,r,z,i = 1;i <= q;i++){
		io.read(l,r,z);l++,r++,z++;
		vec[l - 1].push_back(oper{i,z,-1});
		vec[r].push_back(oper{i,z,1});
	}
	for(int i = 1;i <= n;i++){
		tree::modify(i,1);
		for(auto it : vec[i])
			if(it.flg == 1)ans[it.id] = add(ans[it.id],tree::query(it.z));
			else ans[it.id] = sub(ans[it.id],tree::query(it.z));
	}
	for(int i = 1;i <= q;i++)io.write(ans[i],'\n');
	return 0;
}