zoukankan      html  css  js  c++  java
  • [CF1464F] My Beautiful Madness

    [题目链接]

    http://codeforces.com/contest/1464/problem/F

    [题解]

    判断一个集合是复杂的 , 考虑如何选择一个点 , 只需判断这个点是否满足条件即可。

    结论 : 此点为深度最大的 (LCA)(d) 级祖先 (u)

    显然子树内的路径满足条件。

    下面只需考虑子树外的。

    不妨求出 (u)(d) 级祖先 (v) , 显然所有路径要么在 (v) 的子树内 , 要么穿过 (v)

    求出树的 (DFS) 序 , 树上差分 + 线段树维护路径数量。

    由于离一个点最远的点必然是直径的两个端点之一 , 故线段树维护直径 , 找出 (v) 子树中离 (u) 最远的点 , 判断与 (x) 的大小关系即可。

    时间复杂度 : (O(NlogN))

    [代码]

    #include<bits/stdc++.h>
     
    using namespace std;
     
    typedef long long LL;
     
    #define rep(i , l , r) for (int i = (l); i < (r); ++i)
     
    typedef pair < int , int > pii;
     
    const int MN = 4e5 + 5 , LOG = 20;
     
    int N , Q , o[MN] , id[MN] , eid[MN] , dfn , dep[MN] , cnt[MN];
    vector < int > g[MN];
    int ID[MN] , lg[MN << 1] , tot , st[MN << 1][LOG] , up[MN][LOG] , fa[MN];
     
    inline void dfs(int u) {
    	o[id[u] = ++dfn] = u; st[ID[u] = ++tot][0] = u;
    	up[u][0] = fa[u];
    	for (int i = 1; i < LOG; ++i) up[u][i] = up[up[u][i - 1]][i - 1];
    	for (int v : g[u]) if (v != fa[u]) {
    		fa[v] = u , dep[v] = dep[u] + 1;
    	    dfs(v) , st[++tot][0] = u;
    	}
    	eid[u] = dfn;
    }
    inline int cmp(int x, int y) {return dep[x] > dep[y] ? y : x;}
    inline void build(int n) {
      for (int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
      for (int k = 1; k < LOG; ++k)
        for (int i = 1; i <= n - (1 << k) + 1; ++i) 
          st[i][k] = cmp(st[i][k - 1], st[i + (1 << k - 1)][k - 1]);
    }
    inline int LCA(int u, int v) {
      if (id[u] > id[v]) swap(u, v);
      u = ID[u], v = ID[v]; int t = lg[v - u + 1];
      return cmp(st[u][t], st[v - (1 << t) + 1][t]);
    }
    inline int dist(int u , int v) {
    	return (u && v) ? dep[u] + dep[v] - 2 * dep[LCA(u, v)] : -1;
    }
    inline int jump(int u , int d) {
      if (dep[u] <= d) return 1;
      for (; d; d &= d - 1) u = up[u][__builtin_ctz(d)];
      return u;
    }
    struct BIT {
      int sum[MN];
      inline void add(int x, int y) {for (; x <= N; x += x & -x) sum[x] += y;}
      inline int query(int x) {int res = 0; for (; x; x -= x & -x) res += sum[x]; return res;}
      inline int query(int l, int r) { return query(r) - query(l - 1);}
    } tr;
     
    struct node {
      int x, y, z;
      node(int _x = 0, int _y = 0) {x = _x, y = _y, z = dist(x, y);}
      inline friend bool operator < (const node &A, const node &B) { return A.z < B.z; }
      inline friend node operator ^ (const node &A, const node &B) { return std::max({A, B, node(A.x, B.x), node(A.x, B.y), node(A.y, B.x), node(A.y, B.y)});}
    } diam[MN << 2];
     
    void modify(int p, int l, int r, int pos, bool tp) {
      if (l == r) return void(diam[p] = node(tp * o[pos], tp * o[pos]));
      int mid = l + r >> 1; mid >= pos ? modify(p << 1, l, mid, pos, tp) : modify(p << 1 | 1, mid + 1, r, pos, tp);
      diam[p] = diam[p << 1] ^ diam[p << 1 | 1];
    }
    node query(int p, int l, int r, int L, int R) {
      if (l >= L && r <= R) return diam[p];
      int mid = l + r >> 1;
      if (mid >= L && mid < R) return query(p << 1, l, mid, L, R) ^ query(p << 1 | 1, mid + 1, r, L, R);
      if (mid >= L) return query(p << 1, l, mid, L, R);
      return query(p << 1 | 1, mid + 1, r, L, R);
    }
     
    set < pii > S;
     
    int main() {
     	 
    	 scanf("%d%d" , &N , &Q);
    	 for (int i = 1 , u , v; i < N; ++i) {
    	 	 scanf("%d%d" , &u , &v);
    	 	 g[u].emplace_back(v) , g[v].emplace_back(u);
    	 }
    	 dfs(1) , build(tot);
    	 for (int i = 1 , op , x , y , c = 0; i <= Q; ++i) {
    	 	 scanf("%d%d" , &op , &x);
    	 	 if (op == 3) {
    	 	 	int v = jump(S.rbegin()->second, x), v1 = jump(v, x);
    	        if (tr.query(id[v1], eid[v1]) != c) {puts("No"); continue;}
    	        node tmp = query(1 , 1 , N , id[v1] , eid[v1]);
    	        puts(std::max(dist(tmp.x, v), dist(tmp.y, v)) > x ? "No" : "Yes"); 
    		 } else {
    		 	 scanf("%d", &y); int z = LCA(x, y);
    	         if (op == 1) {
    	       		 ++c; if (!cnt[z]++) S.insert({dep[z], z}), modify(1, 1, N, id[z], 1);
    	        	 tr.add(id[x], 1), tr.add(id[y], 1), tr.add(id[z], -1);
    	      	 } else {
    	        	--c; if (!--cnt[z]) S.erase({dep[z], z}), modify(1, 1, N, id[z], 0);
    	        	tr.add(id[x], -1), tr.add(id[y], -1), tr.add(id[z], 1);
    	         }
    		 }
    	 }
         return 0;
    }
    
  • 相关阅读:
    Thinkphp各种方法知识图谱
    Yii2.0学习笔记:创建登录表单
    Yii2.0学习笔记:第一个页面Saying Hello
    4.1
    4
    flask(3.0)
    flask(2.0)
    flask(1.1)装饰器装饰多个视图函数出现的问题
    flask(1.0)
    Flask之上下文管理机制
  • 原文地址:https://www.cnblogs.com/evenbao/p/14469744.html
Copyright © 2011-2022 走看看