• [洛谷P2056][ZJOI2007]捉迷藏(2019-7-20考试)


    题目大意:有一棵$n(nleqslant10^6)$个点的树,上面所有点是黑点,有$m$次操作:

    1. $C;u$:把点$u$颜色翻转
    2. $G$:问树上最远的两个黑点的距离,若没有黑点输出$0$

    题解:有两个点集,已知它们的直径的端点,可以很快求出点集的并的直径。所有可以用线段树维护所有点的直径。

    卡点:考试时没想到

    C++ Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <queue>
    #include <vector>
    const int maxn = 1e5 + 10, inf = 0x3f3f3f3f;
    
    int head[maxn], cnt;
    struct Edge {
    	int to, nxt;
    } e[maxn << 1];
    inline void addedge(int a, int b) {
    	e[++cnt] = (Edge) { b, head[a] }; head[a] = cnt;
    	e[++cnt] = (Edge) { a, head[b] }; head[b] = cnt;
    }
    
    int n, m;
    int Col[maxn];
    
    int dep[maxn], idx;
    int LG[maxn << 1], pos[maxn], st[22][maxn << 1], tot;
    inline int _min(int a, int b) { return dep[a] < dep[b] ? a : b; }
    inline int _max(int a, int b) { return dep[a] > dep[b] ? a : b; }
    void dfs(int u, int fa = 0) {
    	st[0][++tot] = u, pos[u] = tot;
    	for (int i = head[u], v; i; i = e[i].nxt) {
    		v = e[i].to;
    		if (v != fa) {
    			dep[v] = dep[u] + 1;
    			dfs(v, u);
    			st[0][++tot] = u;
    		}
    	}
    }
    inline int LCA(int x, int y) {
    	static int l, r, len; l = pos[x], r = pos[y];
    	if (l > r) std::swap(l, r);
    	len = LG[r - l + 1];
    	return _min(st[len][l], st[len][r - (1 << len) + 1]);
    }
    inline int dis(int x, int y) {
    	return dep[x] + dep[y] - 2 * dep[LCA(x, y)];
    }
    
    struct Line {
    	int l, r;
    	Line() { }
    	Line(int _l, int _r) : l(_l), r(_r) { }
    	inline friend bool operator ! (const Line &rhs) {
    		return !rhs.l && !rhs.r;
    	}
    	inline Line operator + (const Line rhs) const {
    		if (!*this) return rhs;
    		if (!rhs) return *this;
    		const int x = rhs.l, y = rhs.r;
    		int now = dis(l, r), t; Line ans(l, r);
    		t = dis(l, x); if (now < t) now = t, ans = Line(l, x);
    		t = dis(l, y); if (now < t) now = t, ans = Line(l, y);
    		t = dis(r, x); if (now < t) now = t, ans = Line(r, x);
    		t = dis(r, y); if (now < t) now = t, ans = Line(r, y);
    		t = dis(x, y); if (now < t) now = t, ans = Line(x, y);
    		return ans;
    	}
    } ;
    namespace SgT {
    	Line V[maxn << 2];
    	void modify(int rt, int l, int r, int p, int v) {
    		if (l == r) {
    			V[rt] = Line(v, v);
    			return ;
    		}
    		const int mid = l + r >> 1;
    		if (p <= mid) modify(rt << 1, l, mid, p, v);
    		else modify(rt << 1 | 1, mid + 1, r, p, v);
    		V[rt] = V[rt << 1] + V[rt << 1 | 1];
    	}
    	int query() {
    		return dis(V[1].l, V[1].r);
    	}
    }
    
    int num;
    int main() {
    	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    	std::cin >> n; num = n;
    	for (int i = 1, a, b; i < n; ++i) {
    		std::cin >> a >> b;
    		addedge(a, b);
    	}
    	dfs(1); LG[0] = -1;
    	for (int i = 1; i <= tot; ++i) LG[i] = LG[i >> 1] + 1;
    	for (int i = 1; i <= LG[tot]; ++i)
    		for (int j = 1, len = 1 << i; j + len - 1 <= tot; ++j)
    			st[i][j] = _min(st[i - 1][j], st[i - 1][j + (len >> 1)]);
    	for (int i = 1; i <= n; ++i) SgT::modify(1, 1, n, i, i);
    	std::cin >> m;
    	while (m --> 0) {
    		char op;
    		std::cin >> op;
    		if (op == 'C') {
    			static int x;
    			std::cin >> x;
    			Col[x] ^= 1;
    			if (Col[x]) SgT::modify(1, 1, n, x, 0), --num;
    			else SgT::modify(1, 1, n, x, x), ++num;
    		} else {
    			if (!num) std::cout << "-1
    ";
    			else std::cout << SgT::query() << '
    ';
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Mysql Select 语句中实现的判断
    SQL根据一个字符串集合循环保存数据库
    SQL语句 不足位数补0
    SVN常见错误
    svn架构
    关于EXCEL显示数字
    exception from hresult:0x8000401A(excel文档导出)
    WIN7安装注意事项
    解决卸载时残留目标文件夹的问题
    Installshield执行多条批处理的方法
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/11218061.html
Copyright © 2020-2023  润新知