duxing201606毕业后子承父业继承了一家公司。在公司中,除了duxing201606以外的员工都有一个上司。如果X是Y的上司,Y是Z的上司,那么Y和Z都是X的下属。
duxing201606会经常分配任务给员工,duxing201606非常喜欢团队去完成任务,所以每次duxing201606给X分配任务的时候,会同时给X的所有下属都分配这个任务,该任务的编号为X。
duxing201606想知道如果下达多个命令的话,公司会不会乱套。duxing201606一共会下达3种命令:
1 x 给员工x和他的下属都分配编号为X的任务。
2 x 员工x和他的下属都完成了编号为X的任务。
3 x 输出员工x所有任务中编号最小的那个任务。 如果员工x没有任务就输出-1,否则输出最小的任务编号。
输入
第一行为 n m,代表有n个员工, duxing201606会下达m条命令( 1 <= n, m <= 5e4)。
第二行 n-1个p[i],p[i]代表的是 第 i+1 号员工的上司是谁,( 1<= p[i] <= i)。
第3行到m+2行,每一行输入一个 op x,含义如上。
输出
对于每条命令3,输出答案。
样例输入
9 9
1 2 2 1 5 5 5 8
3 1
3 6
1 5
3 5
3 6
1 1
3 6
2 1
3 6
样例输出
-1
-1
5
5
1
5
正解是:
线段树维护子树。
先求出dfs序。
每次1 X的时候,都往 in[x] out[x]这段区间内插入x
每次2 X的时候,都从 in[x] out[x]这段区间内删除x
每次3 X的时候,和李超树类似,在包含这个in[x]的所有区间中找到最小值。
最小值用set去维护。
直接将线段树的每个区间转化为set,注意这里由于用dfs序直接修改线段树的区间,所以将包含这个数的线段树区间全部更新就行,不用更新到最低,不然会mle。查询同理,因为上面区间一定包含查找点,所以一直查找到这个点最底部,得到答案,这里类似李超树的查询(感觉两个都差不多)
#include<bits/stdc++.h>
#define fi first
#define se second
#define log2(a) log(n)/log(2)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<P, ll> LP;
const ll inf = 1e9 + 10;
const int N = 1e4 + 10;
const ll mod = 1e9+7;
const int base=131;
const double pi=acos(-1);
vector<int> v[N];
set<int> st[N<<2];
int in[N],out[N],num[N];
int n,m;
int ans,cnt;
void dfs(int x)
{
in[x]=++cnt;
num[cnt]=x;
for(auto to:v[x])
{
dfs(to);
}
out[x]=cnt;
}
void init()
{
dfs(1);
}
void add(int val,int ql,int qr,int rt,int l,int r)
{
if(ql<=l&&qr>=r)
{
st[rt].insert(val);
return ;
}
int m=l+r >> 1;
if(ql<=m) add(val,ql,qr,rt<<1,l,m);
if(qr>m) add(val,ql,qr,rt<<1|1,m+1,r);
}
void red(int val,int ql,int qr,int rt,int l,int r)
{
if(ql<=l&&qr>=r)
{
if(st[rt].count(val))
{
st[rt].erase(val);
}
return ;
}
int m=l+r >> 1;
if(ql<=m) red(val,ql,qr,rt<<1,l,m);
if(qr>m) red(val,ql,qr,rt<<1|1,m+1,r);
}
void query(int x,int rt,int l,int r)
{
if(st[rt].size())
{
ans=min(ans,*st[rt].begin());
}
if(l==r) return ;
int m=l+r >> 1;
if(x<=m) query(x,rt<<1,l,m);
if(x>m) query(x,rt<<1|1,m+1,r);
}
int main( )
{
scanf("%d%d",&n,&m);
int x,y;
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
v[x].push_back(i);
}
init();
while(m--)
{
scanf("%d%d",&x,&y);
if(x==1)
{
add(y,in[y],out[y],1,1,n);
}
else if(x==2)
{
red(y,in[y],out[y],1,1,n);
}
else
{
ans=inf;
query(in[y],1,1,n);
if(ans!=inf) printf("%d\n",ans);
else puts("-1");
}
}
}