[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;
}
posted @ 2021-03-02 16:43  evenbao  阅读(116)  评论(0编辑  收藏  举报