DFS序
DFS序是根据DFS遍历树的结点的入栈出栈顺序来给节点赋值的,如下图,黑色的是节点本身的编号,红色的是DFS序以后的数组,数组两个相同的数字之前的标号的的节点,是这个节点的子树,比如红色的2节点,中间有1,3,4三个标号,代表1,3,4是2的子树,将树形结构变成线性结构后,我们就可以用树状数组或者线段树进行操作了
题面
有一家公司有 N 名员工(从 1 到 N 编号),公司的每个员工都有一个直属上司(全公司的领导除外)。如果你是某人的直属上司,那人就是你的下属,他所有的下属也是你的下属。如果你不是任何人的老板,那么你就没有下属,没有直接上司的员工就是整个公司的领导者。所以这意味着N个员工组成了一棵树。
公司通常将一些任务分配给一些员工完成。当一个任务分配给某人时,他/她会将其分配给他/她的所有下属。换句话说,这个人和他/她的所有下属都收到了一个任务。同时。此外,每当员工收到任务时,他/她将停止当前任务(如果他/她有)并开始新的任务。
在公司将一些任务分配给某个员工之后,编写一个程序来帮助确定某个员工的当前任务。
输入
第一行包含一个正整数 T( T <= 10 ),表示测试用例的数量。
对于每个测试用例:
第一行包含一个整数 N (N ≤ 50,000) ,即员工人数。
下面的 N - 1 行每行包含两个整数 u 和 v,这意味着员工 v 是员工 u 的直接老板 (1<=u,v<=N)。
下一行包含一个整数 M (M ≤ 50,000)。
以下 M 行每行包含一条消息,
“C x”表示查询员工 x 的当前任务,
或
“T x y”表示公司将任务 y 分配给员工 x。
(1<=x<=N,0<=y<=10^9)
样例
1
5
4 3
3 2
1 3
5 2
5
C 3
T 2 1
C 3
T 3 2
C 3
输出
Case #1:
-1
1
2
题解
题目上暗示的很明显是一个线段树操作的题,但是建树只能在一维数组的基础上去赋值建树,这道题的关系很显然是树形结构的,不可以直接去建树,就需要引用到知识点DFS序,把一整棵树变成一个一个一维的数组,然后就是正常的区间修改单点查询了。
AC代码
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
#define int long long
#define gcd __gcd
#define endl '\n'
#define mem(x, y) memset(x, y, sizeof(x))
#define inf 0x3f3f3f
#define ninf 0xc0c0c0c0
#define FAST ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
typedef pair<int, int> PII;
const int N = 50010;
bool vis[N];
int ll[N], rr[N];
int idx, n, m;
vector<int> mp[N];
struct tree
{
int l, r, w, lazy;
int mid() { return l + r >> 1; }
} t[N << 2];
void build(int f, int l, int r)
{
t[f] = {l, r, -1, -1};
if (l == r)
return;
int mid = t[f].mid();
build(f << 1, l, mid);
build(f << 1 | 1, mid + 1, r);
}
void pushdown(int f)
{
t[f << 1 | 1].w = t[f << 1 | 1].lazy = t[f << 1].w = t[f << 1].lazy = t[f].lazy;
t[f].lazy = -1;
}
void dfs(int u)
{
ll[u] = ++m;
for (int i = 0; i < mp[u].size(); i++)
{
int v = mp[u][i];
dfs(v);
}
rr[u] = m;
}
void change(int f, int l, int r, int x)
{
if (t[f].l >= l && t[f].r <= r)
{
t[f].w = t[f].lazy = x;
return;
}
if (t[f].lazy != -1)
pushdown(f);
int mid = t[f].mid();
if (r <= mid)
change(f << 1, l, r, x);
else if (l > mid)
change(f << 1 | 1, l, r, x);
else
change(f << 1, l, mid, x), change(f << 1 | 1, mid + 1, r, x);
}
int query(int f, int x)
{
if (t[f].l == x && t[f].r == x)
return t[f].w;
if (t[f].lazy != -1)
pushdown(f);
int mid = t[f].mid();
if (x <= mid)
return query(f << 1, x);
else
return query(f << 1 | 1, x);
}
int cnt;
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
mp[i].clear();
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n - 1; i++)
{
int u, v;
cin >> u >> v;
mp[v].push_back(u);
vis[u] = 1;
}
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
m = 0;
memset(vis, 0, sizeof(ll));
memset(vis, 0, sizeof(rr));
dfs(i);
break;
}
}
build(1, 1, n);
cin >> m;
cout << "Case #" << cnt++ << ":\n";
// cout << m << " \n";
for (int i = 1; i <= m; i++)
{
string a;
cin >> a;
if (a[0] == 'C')
{
int x;
cin >> x;
cout << query(1, ll[x]) << endl;
}
else if (a[0] == 'T')
{
int x, y;
cin >> x >> y;
change(1, ll[x], rr[x], y);
}
}
}
signed main()
{
FAST;
cnt = 1;
int t;
cin >> t;
while (t--)
solve();
}