P5537 【XR-3】系统设计

P5537 【XR-3】系统设计

【XR-3】系统设计

题目描述

小 X 需要你设计一个系统。

这个系统首先需要输入一棵 \(n\) 个点的有根树和一个长度为 \(m\) 的序列 \(a\),接下来需要实现 \(q\) 个操作。

操作分两种:

  1. 1 x l r 表示设定起点为有根树的节点 \(x\),接下来依次遍历 \(l \sim r\)。当遍历到 \(i\) 时,从当前节点走向它的编号第 \(a_i\) 小的儿子。如果某一时刻当前节点的儿子个数小于 \(a_i\),或者已经遍历完 \(l \sim r\),则在这个点停住,并输出这个点的编号,同时停止遍历。
  2. 2 t k 表示将序列中第 \(t\) 个数 \(a_t\) 修改为 \(k\)

输入格式

第一行 \(3\) 个正整数 \(n,m,q\),分别表示树的点数、序列的长度和操作个数。

第二行 \(n\) 个整数 \(f_{1 \dots n}\),其中 \(f_i\) 表示点 \(i\) 在树中的父亲节点编号,特别地,设根节点为 \(rt\),则 \(f_{rt} = 0\)

第三行 \(m\) 个正整数 \(a_{1 \dots m}\),表示序列 \(a\)

接下来 \(q\) 行,每行描述一个操作。

数据范围:

  • \(1 \le n,m,q \le 5 \times 10 ^ 5\)
  • \(1 \le a_i \le n\)
  • 对于操作 \(1\),保证 \(1 \le x \le n\)\(1 \le l \le r \le m\)
  • 对于操作 \(2\),保证 \(1 \le t \le m\)\(1 \le k \le n\)

输出格式

对于每个操作 \(1\),一行一个正整数,表示答案。

用hash[x]来维护从rt走到x的前缀。
(维护的是一个表示路径的数字序列,表示从rt走到x每次走的是编号第几大的儿子)

形式化的:一段路径{1,5,8,3}表示从rt到x这条路径是访问了rt的第1大儿子(记为x1),x1的第5大儿子x2.....

这样,我们处理每次询问时,我们认为[l,r]构成一个序列。
只需要二分出最大的ans,使得从x开始的访问序列[l,ans]合法

将从rt到某个点mid的路径 rt->mid 转化为从x到mid的路径 __x->mid__的方法:

由于我们存的是路径hash,只需要在询问时差分就好了。

那么现在我们面临的问题就只有储存一段区间上路径的hash了:
由于我不想写线段树
由于我想复习一下树状数组(确信)
所以我很自然的想到了树状数组

code:

#include<bits/stdc++.h>
const int N=5e5+5;
const int P=131313131;
using namespace std;
typedef unsigned long long ull;
int n,m,rt,q;
int dep[N],fa[N],a[N];
ull hsh[N],p[N],t[N],p2[N];
unordered_map<ull,int> Map;
vector<int> G[N];
void dfs(int u,int f)
{
  int tot=0;
  dep[u]=dep[f]+1;
  for(int v:G[u])
  {
  	tot++;
  	hsh[v]=hsh[u]*P+tot;
  	Map[hsh[v]]=v;
  	dfs(v,u);
  }
}
int lb(int x)
{
  return -x&x;
}
void add(int x,ull y)
{
  for(int i=x;i<=n;i+=lb(i))
  {
  	t[i]+=y;
  	y*=p[lb(i)];
  }
}
ull query_pos(int x)
{
  ull y=1,res=0;
  for(int i=x;i;i-=lb(i))
  {
  	res+=t[i]*y;
  	y*=p[lb(i)];
  }
  return res;
}
ull query_range(int l,int r)
{
  return query_pos(r)-query_pos(l-1)*p[r-l+1];
}
bool check(int x,int L,int mid)
{
  ull ask=hsh[x]*p[mid-L+1]+query_range(L,mid);
  return Map.find(ask)!=Map.end();
}
void work()
{
  cin>>n>>m>>q;
  for(int i=1;i<=n;i++)
  {
  	scanf("%d",&fa[i]);
  	if(!fa[i])rt=i;
  	else
  	{
  		G[fa[i]].push_back(i);
  	}
  }
  p[0]=1;
  for(int i=1;i<=m;i++)
  {
  	p[i]=p[i-1]*P;
  }
  for(int i=1;i<=n;i++)
  {
  	sort(G[i].begin(),G[i].end());
  }
  dfs(rt,0);
  for(int i=1;i<=m;i++)
  {
  	scanf("%d",&a[i]);
  	add(i,a[i]);
  }
  for(int i=1,opt,l,r,x;i<=q;i++)
  {
  	scanf("%d",&opt);
  	if(opt==1)
  	{
  		scanf("%d%d%d",&x,&l,&r);
  		int L=l;l--;
  		while(l<r)
  		{
  			int mid=l+r+1>>1;
  			check(x,L,mid)? l=mid : r=mid-1;
  		}
  		ull val=hsh[x]*p[l-L+1]+query_range(L,l);
  		int ans=Map[val];
  		printf("%d\n",ans? ans:x);
  	}
  	else
  	{
  		scanf("%d%d",&l,&x);
  		add(l,x-a[l]);
  		a[l]=x;
  	}
  }
}
int main()
{
  freopen("P5537.in","r",stdin);freopen("P5537.out","w",stdout);
  work();
}
posted @ 2024-12-06 11:43  liuboom  阅读(33)  评论(0)    收藏  举报