3626: [LNOI2014]LCA

3626: [LNOI2014]LCA

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1817   Solved: 702
[ Submit][ Status][ Discuss]

Description

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点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

HINT

共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。


Source

[ Submit][ Status][ Discuss]



两个点的LCA等价于。。

如果每个点开个bitset,从根到它的路径上存在的点标1

两个点的bitset进行&,,结果的1的个数就是深度

考虑没有l的限制

一个点到根的路径上所有点权+1

[1,r]范围内,原式的ans等价于从z点走到根,权值求和

那么题目有l的限制?

离线一下就好


赋值操作树链剖分就好

#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 5E4 + 10;
const int T = 80;
typedef long long LL;
const LL mo = 201314;

struct Q{
	int z,pos,Multi,flag;
	Q(int _z = 0,int _pos = 0,int _Multi = 0,int _flag = 0) {
		z = _z; pos = _pos; Multi = _Multi; flag = _flag;
	}
	bool operator < (const Q &b) const{return flag < b.flag;}
}query[maxn*2];

int n,m,dfs_clock,cnt,fa[maxn],len[maxn],pos[maxn],
	siz[maxn],Nex[maxn],po[maxn],Root[maxn],dfn[maxn];
LL c[maxn*T],Add[maxn*T],ans[maxn];
bool Huge[maxn];

vector <int> v[maxn];

void dfs1(int x)
{
	siz[x] = 1; int Max = 0,Pos;
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		dfs1(to); siz[x] += siz[to];
		if (siz[to] > Max) Max = siz[to],Pos = to;
	}
	if (siz[x] > 1) Huge[Pos] = 1,Nex[x] = Pos;
}

void dfs2(int x,int Len)
{
	dfn[x] = ++dfs_clock; po[dfs_clock] = x;
	if (Huge[x]) ++Len;
	if (Nex[x]) dfs2(Nex[x],Len);
	if (siz[x] == 1 && Huge[x]) {len[x] = Len; pos[x] = 1;}
	if (siz[x] > 1 && Huge[x]) {len[x] = len[Nex[x]]; pos[x] = pos[Nex[x]] + 1;}
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if (Huge[to]) continue;
		dfs2(to,0);
	}
}

int getint()
{
	char ch = getchar();
	int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9') ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

void pushdown(int o,int l,int r)
{
	if (Add[o]) {
		if (l == r) return;
		int lc = 2*o,rc = 2*o + 1,mid = (l+r) >> 1;
		c[lc] += 1LL*(mid - l + 1)*Add[o]; Add[lc] += Add[o];
		c[rc] += 1LL*(r - mid)*Add[o]; Add[rc] += Add[o];
		Add[o] = 0;
	}
}

void Insert(int o,int l,int r,int ql,int qr)
{
	if (ql <= l && r <= qr) {
		c[o] += 1LL*(r - l + 1); 
		++Add[o]; return;
	}
	int mid = (l + r) >> 1;
	pushdown(o,l,r);
	if (ql <= mid) Insert(2*o,l,mid,ql,qr);
	if (qr > mid) Insert(2*o+1,mid+1,r,ql,qr);
	c[o] = c[2*o] + c[2*o+1];
}

LL Query(int o,int l,int r,int ql,int qr)
{
	if (l > r) return 0;
	if (ql <= l && r <= qr) return c[o];
	pushdown(o,l,r);
	int mid = (l + r) >> 1;
	LL ret = 0;
	if (ql <= mid) ret += Query(2*o,l,mid,ql,qr);
	if (qr > mid) ret += Query(2*o+1,mid+1,r,ql,qr);
	return ret;
}

void Solve(int now)
{
	LL sum = 0;
	for (int z = query[now].z; z; z = fa[z])
		if (!Huge[z]) sum += Query(1,1,n,dfn[z],dfn[z]);
		else {
			int L = dfn[z] - len[z] + pos[z];
			sum += Query(1,1,n,L,dfn[z]);
			z = po[L];
		}
	ans[query[now].pos] += 1LL*query[now].Multi*sum;
} 

int main()
{
	#ifdef DMC
		freopen("lca1.in","r",stdin);
		freopen("test.txt","w",stdout);
	#endif
	
	n = getint(); m = getint();
	for (int i = 2; i <= n; i++) {
		int x = getint(); fa[i] = ++x;
		v[x].push_back(i);
	}
	dfs1(1); dfs2(1,0);
	
	int tot = 0;
	for (int i = 1; i <= m; i++) {
		int l = getint(),r = getint() + 1,z = getint() + 1;
		if (l) query[++tot] = Q(z,i,-1,l);
		query[++tot] = Q(z,i,1,r);
	}
	sort(query + 1,query + tot + 1);
	int tail = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = i; j; j = fa[j])
			if (!Huge[j]) Insert(1,1,n,dfn[j],dfn[j]);
			else {
				int L = dfn[j] - len[j] + pos[j];
				Insert(1,1,n,L,dfn[j]);
				j = po[L];
			}
		while (tail <= tot && query[tail].flag <= i) Solve(tail++);
	}
	for (int i = 1; i <= m; i++) printf("%lld\n",ans[i] % mo);
	return 0;
}

此题用可持久化线段树可以做到在线询问,但是,,苟蒻不会写。GG

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值