P4092[HEOI2016/TJOI2016]树(题解)

这里有一篇题解。

P4092[HEOI2016/TJOI2016]树(题解)

点我

Ready.

dfs序:
把原树按照dfs的序号编号,先dfs到的节点dfs序小
例如下图中就是样例,黑体是dfs序,蓝体是题目给定序(原序)
出错啦

Attention.

dfs序与原序要分清
修改时并不能直接赋值,要取最大值。

Solution.

先把原数赋予按照dfs序,以及逆dfs序。
现在经观察得,每一个点的子孙便是【它,它的最右子节点】中所有整数。
接下来便可以向线段树思考了,它需要维护区间最大值。
支持区间改最大值,查最大值。

Coding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const ll Max=100005;
struct data //线段树节点
{
ll num,flag;
data() {num=1;flag=0;}
data(ll a,ll b):num(a),flag(b) {}
};
struct tree //题目中给的树
{
vector<ll>b[Max];
ll dfs_xu[Max],ni_dfs_xu[Max],size;
inline void clean() //清空
{
for(ll i=0;i<Max;i++) b[i].clear();
}
inline void add_edge(ll x,ll y) //加边
{
b[x].push_back(y);
}
void dfs(ll now,ll fa) //求dfs序
{
if(now==1) size=0;
size++;
dfs_xu[now]=size;
for(ull i=0;i<b[now].size();i++)
if(b[now][i]!=fa)
dfs(b[now][i],now);
}
inline void ni_dfs() //求逆dfs序
{
for(ll i=1;i<=size;i++) ni_dfs_xu[dfs_xu[i]]=i;
}
ll rightest(ll n) //n是原序,rightest是原序;
{
if(b[n].size()==0) return n;
return rightest(b[n][b[n].size()-1]);
}
};
struct cut_tree //线段树
{
data tre[Max<<2];
inline void down(ll rt,ll l,ll r) //下推标记(有点烦)
{
if(!tre[rt].flag) return;
if(l==r)
{
tre[rt].num=max(tre[rt].num,tre[rt].flag); //注意!!!不应该直接赋值
tre[rt].flag=0;
return;
}
tre[rt<<1].flag=max(tre[rt].flag,tre[rt<<1].flag);
tre[rt<<1|1].flag=max(tre[rt].flag,tre[rt<<1|1].flag);
tre[rt].num=max(tre[rt].num,tre[rt].flag);
tre[rt].flag=0;
}
inline void up(ll rt,ll l,ll r) //上推数值
{
tre[rt].num=max(tre[rt<<1].num,tre[rt<<1|1].num);
}
ll csearch(ll rt,ll l,ll r,ll d) //查询
{
down(rt,l,r);
if(l==d&&r==d) return tre[rt].num;
if(d<=(l+r)>>1) return csearch(rt<<1,l,(l+r)>>1,d);
return csearch(rt<<1|1,((l+r)>>1)+1,r,d);
}
void change(ll rt,ll l,ll r,ll dl,ll dr,ll dc) //修改
{
if(l>r) return;
if(dl>r) return;
if(l>dr) return;
if(dl<=l&&r<=dr)
{
tre[rt].flag=max(tre[rt].flag,dc);
return;
}
change(rt<<1,l,(l+r)>>1,dl,dr,dc);
change(rt<<1|1,((l+r)>>1)+1,r,dl,dr,dc);
up(rt,l,r);
}
};
cut_tree tr;
tree a;
int main()
{
ll n,q;
scanf("%lld%lld",&n,&q);
a.clean();
for(ll i=1;i<n;i++)
{
ll x,y;
scanf("%lld%lld",&x,&y);
a.add_edge(x,y);
}
a.dfs(1,0);
a.ni_dfs();
while(q--)
{
char c;ll x;
cin>>c;scanf("%lld",&x);
if(c=='C')
{
ll y=a.rightest(x);
tr.change(1,1,n,a.dfs_xu[x],a.dfs_xu[y],a.dfs_xu[x]); //此处要搞清!!!
}
if(c=='Q')
{
ll y=tr.csearch(1,1,n,a.dfs_xu[x]);
printf("%lld\n",a.ni_dfs_xu[y]); //还有此处
}
}
return 0;
}