【LNOI 2014】 LCA

【題目鏈接】

         點擊打開鏈接

【算法】

           考慮求lca(x,y)的深度

           我們可以將從根到x路徑上的點都打上標記,然後,詢問y到根上路徑的權值和

           那麼,求sigma(depth(lca(i,z)))(l <= i <= r ),我們可以將區間[l,r]中的點依次打上標記,然後,詢問點z到根路徑

           上的權值和

           因爲此題有多組詢問,顯然在線很難做,因此,我們考慮離線計算答案

           求sigma(depth(lca(i,z))) (l <= i <= r),我們可以轉化爲

           sigma(depth(lca(i,z))) ( 0 <= i <= r) - sigma(depth(lca(i,z))) (0 <= i <= l - 1)

           那麼,樹鏈剖分/動態樹都可以解決這道題,樹鏈剖分的時間複雜度是O((n + q) log(n)^2)的,而動態樹的時間複雜度是             O((n + q) log(n))的

【代碼】

           由於筆者太弱,不會動態樹,所以這份代碼是樹鏈剖分的寫法

         

#include<bits/stdc++.h>
using namespace std;
#define MAXM 50010
const int P = 201314;

struct Edge
{
	int to,nxt;
} e[MAXM];
struct Query
{
	int pos,opt,z,id;	
} q[MAXM*2];

int i,n,m,f,timer,tot,cnt,now,l,r,z;
int dfn[MAXM],size[MAXM],top[MAXM],head[MAXM],son[MAXM],ans[MAXM],fa[MAXM];

struct SegmentTree
{
		struct Node
		{
				int l,r;
				int sum,tag;
		} Tree[MAXM*4];
		inline void build(int index,int l,int r)
		{
				int mid;
				Tree[index].l = l; Tree[index].r = r;
				Tree[index].sum = Tree[index].tag = 0;
				if (l == r) return;
				mid = (l + r) >> 1;
				build(index<<1,l,mid);
				build(index<<1|1,mid+1,r);
		}
		inline void pushdown(int index)
		{
				int l = Tree[index].l,r = Tree[index].r;
				int mid = (l + r) >> 1;
				if (Tree[index].tag)
				{
						Tree[index<<1].sum = (Tree[index<<1].sum + (mid - l + 1) * Tree[index].tag) % P;
						Tree[index<<1|1].sum = (Tree[index<<1|1].sum + (r - mid) * Tree[index].tag) % P;
						Tree[index<<1].tag = (Tree[index<<1].tag + Tree[index].tag) % P;
						Tree[index<<1|1].tag = (Tree[index<<1|1].tag + Tree[index].tag) % P;
						Tree[index].tag = 0;
				}
		}
		inline void update(int index)
		{
				Tree[index].sum = (Tree[index<<1].sum + Tree[index<<1|1].sum) % P;
		}
		inline void modify(int index,int l,int r,int val)
		{
				int mid;
				if (Tree[index].l == l && Tree[index].r == r)
				{
						Tree[index].sum = (Tree[index].sum + (r - l + 1) * val) % P;
						Tree[index].tag = (Tree[index].tag + val) % P;
						return;
				}
				pushdown(index);
				mid = (Tree[index].l + Tree[index].r) >> 1;
				if (mid >= r) modify(index<<1,l,r,val);
				else if (mid + 1 <= l) modify(index<<1|1,l,r,val);
				else
				{
						modify(index<<1,l,mid,val);
						modify(index<<1|1,mid+1,r,val);
				}
				update(index);
		}
		inline int query(int index,int l,int r)
		{
				int mid;
				if (Tree[index].l == l && Tree[index].r == r) return Tree[index].sum;
				pushdown(index);
				mid = (Tree[index].l + Tree[index].r) >> 1;
				if (mid >= r) return query(index<<1,l,r);
				else if (mid + 1 <= l) return query(index<<1|1,l,r);
				else return (query(index<<1,l,mid) + query(index<<1|1,mid+1,r)) % P;
		}
} T;
inline bool cmp(Query a,Query b) 
{
	return a.pos < b.pos;
}
inline void add(int u,int v)
{
		tot++;
		e[tot] = (Edge){v,head[u]};
		head[u] = tot;
}
inline void dfs1(int u)
{
		int i,v;
		size[u] = 1;
		for (i = head[u]; i; i = e[i].nxt)
		{
				v = e[i].to;
				dfs1(v);
				size[u] += size[v];
				if (size[v] > size[son[u]] || !son[u]) son[u] = v;
		}
}
inline void dfs2(int u,int tp)
{
		int i,v;
		top[u] = tp;
		dfn[u] = ++timer;
		if (son[u]) dfs2(son[u],tp); 	
		for (i = head[u]; i; i = e[i].nxt)
		{
				v = e[i].to;
				if (son[u] != v) dfs2(v,v);
		}
}
inline void modify(int pos)
{
		int tp = top[pos];
		while (tp)
		{
				T.modify(1,dfn[tp],dfn[pos],1);
				pos = fa[tp]; tp = top[pos];
		}
		T.modify(1,1,dfn[pos],1);
}
inline int query(int pos)
{
		int tp = top[pos],ans = 0;
		while (tp)
		{
				ans = (ans + T.query(1,dfn[tp],dfn[pos])) % P;
				pos = fa[tp]; tp = top[pos];
		}
		ans = (ans + T.query(1,1,dfn[pos])) % P;
		return ans;
}

int main()
{
	
		scanf("%d%d",&n,&m);
		for (i = 1; i < n; i++) 
		{
				scanf("%d",&fa[i]);
				add(fa[i],i);	
		}
		dfs1(0);
		dfs2(0,0);
		T.build(1,1,timer);
		for (i = 1; i <= m; i++) 
		{
				scanf("%d%d%d",&l,&r,&z);
				if (l != 0) q[++cnt] = (Query){l-1,-1,z,i};
				q[++cnt] = (Query){r,1,z,i};
		}
		sort(q+1,q+cnt+1,cmp);
		now = -1; 
		for (i = 1; i <= cnt; i++)
		{
				while (now + 1 <= q[i].pos) 
				{
						now++;
						modify(now);
				} 
				if (q[i].opt == 1) ans[q[i].id] = (ans[q[i].id] + query(q[i].z)) % P;
				else ans[q[i].id] = (ans[q[i].id] - query(q[i].z) + P) % P;
		}
		for (i = 1; i <= m; i++) printf("%d\n",ans[i]);
		
		return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章