• [BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】


    题目链接: BZOJ - 3626

    题目分析

    考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就是从 y 到 Root 的路径上的点权和。

    这个方法是可以叠加的,这是非常有用的一点。如果我们把 [l, r] 的每个点到 Root 的路径上所有点的权值 +1,再求出从 c 到 Root 的路径点权和,即为 [l, r] 中所有点与 c 的 LCA 的 Depth 和。

    不仅满足可加性,还满足可减性,这就更好了!

    那么我们就可以对每个询问 [l, r] 做一个差分,用 Query(r) - Query(l - 1) 作为答案。这样就有一种离线算法:将 n 个点依次操作,将其到 Root 的路径上的点权值 +1 ,然后如果这个点是某个询问的 l - 1 或 r ,就用那个询问的 c 求一下到 Root 的路径和,算入答案中。

    Done! 

    写代码的时候忘记 % Mod 真是弱...

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <vector>
    
    using namespace std;
    
    const int MaxN = 50000 + 5, Mod = 201314;
    
    int n, m, Index;
    int Father[MaxN], Depth[MaxN], Size[MaxN], Son[MaxN], Top[MaxN], Pos[MaxN];
    int T[MaxN * 4], D[MaxN * 4], Len[MaxN * 4], Ans[MaxN], Q[MaxN];
    
    vector<int> BA[MaxN], EA[MaxN];
    
    struct Edge 
    {
    	int v;
    	Edge *Next;
    } E[MaxN], *P = E, *Point[MaxN];
    
    inline void AddEdge(int x, int y) {
    	++P; P -> v = y;
    	P -> Next = Point[x]; Point[x] = P;
    }
    
    int DFS_1(int x, int Dep) {
    	Depth[x] = Dep;
    	Size[x] = 1;
    	int SonSize, MaxSonSize;
    	SonSize = MaxSonSize = 1;
    	for (Edge *j = Point[x]; j; j = j -> Next) {
    		SonSize = DFS_1(j -> v, Dep + 1);
    		if (SonSize > MaxSonSize) {
    			MaxSonSize = SonSize;
    			Son[x] = j -> v;
    		}
    		Size[x] += SonSize;
    	}
    	return Size[x];
    }
    
    void DFS_2(int x) {
    	if (x == Son[Father[x]]) Top[x] = Top[Father[x]];
    	else Top[x] = x;
    	Pos[x] = ++Index;
    	if (Son[x] != 0) DFS_2(Son[x]);
    	for (Edge *j = Point[x]; j; j = j -> Next) 
    		if (j -> v != Son[x]) DFS_2(j -> v);
    }
    
    void Build_Tree(int x, int s, int t) {
    	Len[x] = t - s + 1;
    	D[x] = T[x] = 0;
    	if (s == t) return;
    	int m = (s + t) >> 1;
    	Build_Tree(x << 1, s, m);
    	Build_Tree(x << 1 | 1, m + 1, t);
    }
    
    inline void Update(int x) {
    	T[x] = T[x << 1] + T[x << 1 | 1];
    	T[x] %= Mod;
    }
    
    inline void Paint(int x, int Num) {
    	T[x] += Num * Len[x];
    	T[x] %= Mod;
    	D[x] += Num;
    	D[x] %= Mod;
    }
    
    inline void PushDown(int x) {
    	if (D[x] == 0) return;
    	Paint(x << 1, D[x]);
    	Paint(x << 1 | 1, D[x]);
    	D[x] = 0;
    }
    
    void Add(int x, int s, int t, int l, int r) {
    	if (l <= s && r >= t) {
    		Paint(x, 1);
    		return;
    	}
    	PushDown(x);
    	int m = (s + t) >> 1;
    	if (l <= m) Add(x << 1, s, m, l, r);
    	if (r >= m + 1) Add(x << 1 | 1, m + 1, t, l, r);
    	Update(x);
    }
    
    void EAdd(int x) {
    	int fx;
    	fx = Top[x];
    	while (fx != 1) {
    		Add(1, 1, n, Pos[fx], Pos[x]);
    		x = Father[fx];
    		fx = Top[x];
    	}
    	Add(1, 1, n, Pos[1], Pos[x]);
    }
    
    int Get(int x, int s, int t, int l, int r) {
    	if (l <= s && r >= t) return T[x];
    	int ret = 0;
    	PushDown(x);
    	int m = (s + t) >> 1;
    	if (l <= m) ret += Get(x << 1, s, m, l, r);
    	if (r >= m + 1) ret += Get(x << 1 | 1, m + 1, t, l, r);
    	return ret % Mod;
    }
    
    int EGet(int x) {
    	int ret = 0, fx;
    	fx = Top[x];
    	while (fx != 1) {
    		ret += Get(1, 1, n, Pos[fx], Pos[x]);
    		ret %= Mod;
    		x = Father[fx];
    		fx = Top[x];
    	}
    	ret += Get(1, 1, n, Pos[1], Pos[x]);
    	return ret % Mod;
    }
    
    int main() 
    {
    	scanf("%d%d", &n, &m);
    	int a, b, c;
    	for (int i = 2; i <= n; ++i) {
    		scanf("%d", &a);
    		++a;
    		Father[i] = a;
    		AddEdge(a, i);
    	}
    	DFS_1(1, 1);
    	Index = 0;
    	DFS_2(1);
    	Build_Tree(1, 1, n);
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d%d%d", &a, &b, &c);
    		++a; ++b; ++c;
    		Q[i] = c;
    		BA[a - 1].push_back(i);
    		EA[b].push_back(i);
    	}
    	for (int i = 1; i <= n; ++i) {
    		EAdd(i);
    		for (int j = 0; j < BA[i].size(); ++j) 
    			Ans[BA[i][j]] -= EGet(Q[BA[i][j]]);
    		for (int j = 0; j < EA[i].size(); ++j) 
    			Ans[EA[i][j]] += EGet(Q[EA[i][j]]);
    	}
    	for (int i = 1; i <= m; ++i) printf("%d
    ", (Ans[i] + Mod) % Mod);
    	return 0;
    }
    

      

  • 相关阅读:
    程序员开发工作之算法和架构
    iOS开发学习概述及知识整理
    git基本技巧及进阶
    使用命令行工具运行Xcode 7 UI Tests
    技巧集锦2
    Xcode开发小问题集锦
    Xcode 7如何 免费 真机调试iOS应用
    常用shell script 珍藏
    多线程学习7--CountDownLatch
    学习多线程6---栅栏
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4229141.html
Copyright © 2020-2023  润新知