zoukankan      html  css  js  c++  java
  • 树上莫队

    SP10707 COT2 - Count on a tree II - 洛谷

    • 给定 (n) 个结点的树,每个结点有一种颜色。
    • (m) 次询问,每次询问给出 (u,v),回答 (u,v) 之间的路径上的结点的不同颜色数。

    很显然,如果是在序列上的化就是最基础的莫队模板题

    考虑转化到序列上

    欧拉序列(DFS)

    可以解决这个问题

    对于询问 ((x,y))(x) 是在 (DFS) 中先出现的那个

    分为两种情况:

    • (x == lca(x,y)) , 则对应的区间是 ([in(x),in(y)]) 中出现次数为一的点 ,如上图红色询问
    • (x eq lca(x,y)) , 则对应区间是 ([out(x), in(y)]) 中出现次数为一的点,加上 (lca)

    对于翻转操作,可以用一个数组 (st) 进行标识,增添和删除其实都是一样的

    /*
     * @Author: zhl
     * @Date: 2020-11-19 15:34:09
     */
    #include<bits/stdc++.h>
    #pragma GCC optimize(3)
    #define pb(x) push_back(x)
    using namespace std;
    
    const int N = 1e5 + 10;
    vector<int>G[N];
    
    int n, m, len, ID[N], ans[N];
    int w[N], nums[N], in[N], out[N], ord[N];
    int tot, dep[N], f[N][32], cnt[N], st[N];
    
    void add(int x, int& res) {
    	st[x] ^= 1;
    	if (!st[x]) {
    		if (!--cnt[w[x]])res--;
    	}
    	else {
    		if (!cnt[w[x]]++)res++;
    	}
    }
    
    
    void dfs(int u, int p) {
    	in[u] = ++tot;
    	ord[tot] = u;
    
    	dep[u] = dep[p] + 1; f[u][0] = p;
    	for (int x = 1; (1 << x) < dep[u]; x++) {
    		f[u][x] = f[f[u][x - 1]][x - 1];
    	}
    	for (int v : G[u]) {
    		if (v == p)continue;
    		dfs(v, u);
    	}
    	out[u] = ++tot;
    	ord[tot] = u;
    }
    
    int LCA(int x, int y) {
    	if (dep[x] < dep[y])swap(x, y);
    	while (dep[x] != dep[y]) {
    		int u = dep[x] - dep[y];
    		int v = 0;
    		while (!(u & (1 << v)))v++;
    		x = f[x][v];
    	}
    
    	while (x != y) {
    		int v = 0;
    		while (f[x][v] != f[y][v])v++;
    		x = f[x][max(0, v - 1)]; y = f[y][max(0, v - 1)];
    	}
    	return x;
    }
    
    struct Query {
    	int id, l, r, lca;
    	bool operator < (const Query& b)const {
    		if (ID[l] != ID[b.l])return ID[l] < ID[b.l];
    		return r < b.r;
    	}
    }q[N];
    
    int main() {
    	scanf("%d%d", &n, &m); int numID = 0;
    	for (int i = 1; i <= n; i++)scanf("%d", w + i), nums[++numID] = w[i];
    
    	sort(nums + 1, nums + 1 + n);
    	numID = unique(nums + 1, nums + 1 + n) - nums - 1;
    
    	for (int i = 1; i <= n; i++)w[i] = lower_bound(nums + 1, nums + 1 + numID, w[i]) - nums;
    
    	for (int i = 1; i < n; i++) {
    		int a, b; scanf("%d%d", &a, &b);
    		G[a].pb(b); G[b].pb(a);
    	}
    
    	dfs(1, 0);
    	len = sqrt(tot);
    	for (int i = 1; i <= tot; i++)ID[i] = i / len;
    
    	for (int i = 1; i <= m; i++) {
    		int x, y; scanf("%d%d", &x, &y);
    		int lca = LCA(x, y);
    		if (in[x] > in[y])swap(x, y);
    
    		if (lca == x) {
    			q[i] = { i,in[x],in[y],0 };
    		}
    		else {
    			q[i] = { i,out[x],in[y],lca };
    		}
    	}
    	sort(q + 1, q + 1 + m);
    
    	int res = 0, l = 1, r = 0;
    	for (int i = 1; i <= m; i++) {
    		int ql = q[i].l, qr = q[i].r, lca = q[i].lca;
    
    		if (lca != 0)add(lca, res);
    		while (l < ql)add(ord[l++], res);
    		while (l > ql)add(ord[--l], res);
    		while (r < qr)add(ord[++r], res);
    		while (r > qr)add(ord[r--], res);
    
    		ans[q[i].id] = res;
    		if (lca != 0)add(lca, res);
    	}
    	for (int i = 1; i <= m; i++)printf("%d
    ", ans[i]);
    }
    
  • 相关阅读:
    activiti初学
    Python微信跳一跳外挂
    Linux下将Mongodb单机升级至副本集
    Linux安装Mongodb4.2
    Python3 acm基础输入输出
    Nginx安装图片模块出错,提示fatal error: curl/curl.h
    基于Redis的分布式锁两种实现方式
    Nginx常用模块安装命令
    Nginx安装Nginx-echo模块
    Nginx使用图片处理模块
  • 原文地址:https://www.cnblogs.com/sduwh/p/14032539.html
Copyright © 2011-2022 走看看