• 点分治入门学习笔记


    模板链接 (Click) (Here)

    终于又打开了一个天坑。。。。点分治真的是好东西呢(QwQ)

    点分治的核心思想在于把问题划分为每一个点可以统计的形式,然后对树上的点进行分治。为了保证复杂度为(log),需要每次都找询问子树的重心。

    可以很好的解决关于所有链信息的询问。通常离线。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int M = 110;
    const int N = 10010;
    const int INF = 10000010;
    
    int n, m, cnt, head[N];
    
    struct edge {
    	int nxt, to, w;
    
    	edge (int _nxt = 0, int _to = 0, int _w = 0) {
    		nxt = _nxt, to = _to, w = _w;
    	}
    	
    }e[N << 1];
    
    void add_len (int u, int v, int w) {
    	e[++cnt] = edge (head[u], v, w); head[u] = cnt;
    	e[++cnt] = edge (head[v], u, w); head[v] = cnt;
    }
    
    int rt, sum, sz[N], qry[M], rem[N], res[M], dis[N], maxp[N];
    
    bool vis[N], have[INF];
    
    void get_root (int u, int fa) {
    	sz[u] = 1, maxp[u] = 0;
    	for (int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (v != fa && !vis[v]) { //vis 限制只访问这棵子树的信息。
    			get_root (v, u);
    			sz[u] += sz[v];
    			maxp[u] = max (maxp[u], sz[v]);
    		}
    	}
    	maxp[u] = max (maxp[u], sum - sz[u]); //sum 是当前子树大小
    	if (maxp[u] < maxp[rt]) rt = u;
    }
    
    void get_dis (int u, int fa) {
    	rem[++rem[0]] = dis[u];
    	for (int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (!vis[v] && v != fa) {
    			dis[v] = dis[u] + e[i].w;
    			get_dis (v, u);
    		}
    	}
    }
    
    queue <int> q;
    
    void calc (int u) {
    	for (int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (!vis[v]) {
    			rem[0] = 0, dis[v] = e[i].w;
    			get_dis (v, u);
    			for (int j = 1; j <= rem[0]; ++j) {
    				for (int k = 1; k <= m; ++k) {
    					if (qry[k] >= rem[j]) {
    						res[k] |= have[qry[k] - rem[j]];
    					}
    				}
    			}
    			for (int j = 1; j <= rem[0]; ++j) {
    				q.push (rem[j]); have[rem[j]] = true;
    			}
    		}
    	}
    	while (!q.empty ()) have[q.front ()] = false, q.pop ();
    }
    
    void solve (int u) {
    	//have[i] -> 是否存在 dis = i 的路径
    	vis[u] = have[0] = true; calc (u);
    	//只能访问 u 的子树, 计算 u 子树的状态
    	for (int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (!vis[v]) {
    			sum = sz[v];
    			maxp[rt = 0] = INF;
    			get_root (v, 0);
    			solve (rt);
    		}
    	}
    }
    
    int main () {
    	cin >> n >> m;
    	for (int i = 1; i <= n - 1; ++i) {
    		static int u, v, w;
    		cin >> u >> v >> w;
    		add_len (u, v, w);
    	}
    	for (int i = 1; i <= m; ++i) cin >> qry[i];
    	maxp[rt] = sum = n;
    	get_root (1, 0);
    	solve (rt);
    	for (int i = 1; i <= m; ++i) {
    		puts (res[i] ? "AYE" : "NAY");
    	}
    } 
    
    
  • 相关阅读:
    Go标准库Context
    事务并发处理: DB+ORM+逻辑代码
    日志:slf4j+log4j+maven配置
    Shiro workshop
    JSP Workshop
    sql records
    Java内存模型(JMM)
    Application, JDBC, 数据库连接池, Session, 数据库的关系
    Java位操作全面总结
    Effective Java总结
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10515652.html
Copyright © 2020-2023  润新知