算法实现:一次dfs + 求和indexed tree的多次update,query完成
- 由于要查找所有祖先节点的值,比自己大的个数,dfs过程中,祖先节点可大,可小求和有困难,所以使用indexed tree来求和
- 对每个节点来说其实是求一个自身到根节点的区间中比自己大的个数的和
- 并且为了只走一次dfs,所以当进入V节点时,update(V,1),离开节点时update(V,-1),保证了祖先节点不会重复计算
- 注意:栈内存给3M的话,20个case都能通过,本社那边的case可能数据量较大,所以把dfs修改为使用stack的非递归实现
测试用例:
2
7 7
7 4
6 2
7 5
6 1
1 3
7 6
10 2
1 3
5 4
5 8
5 9
9 1
2 5
9 6
1 10
5 7
(输出)
#1 9
#2 7
public class 路径管理 {private static final HashMap<Integer, LinkedList<Integer>> adj = new HashMap<>();private static final LinkedList<Integer> stack = new LinkedList<>();private static final long[] tree = new long[260_005];private static int N, start, offset;public static void main(String[] args) throws Exception {StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));in.nextToken();int T = (int) in.nval;for (int t = 1; t <= T; t++) {in.nextToken();N = (int) in.nval;in.nextToken();start = (int) in.nval;Arrays.fill(tree, 0);for (int i = 1; i < N; i++) {in.nextToken();int a = (int) in.nval;in.nextToken();int b = (int) in.nval;adj.computeIfAbsent(a, l -> new LinkedList<>()).add(b);}offset = 1;while (offset < N)offset <<= 1;offset--;System.out.println("#" + t + " " + dfs());}}private static long dfs() {stack.add(start);update(start, 1);long sum = 0;while (!stack.isEmpty()) {LinkedList<Integer> next = adj.get(stack.peekLast());if (next == null || next.isEmpty()) {int out = stack.pollLast();update(out, -1);} else {int in = next.poll();sum += query(in + 1, N);stack.add(in);update(in, 1);}}return sum;}private static void update(int i, int v) {i = offset + i;while (i > 0) {tree[i] += v;i >>= 1;}}private static long query(int s, int e) {long sum = 0;s += offset;e += offset;while (s <= e) {if (s % 2 == 1)sum += tree[s];if (e % 2 == 0)sum += tree[e];s = (s + 1) >> 1;e = (e - 1) >> 1;}return sum;}}
