hihocoder1065 点分治 【 全图传送 】

来源:互联网 发布:恩尼格玛密码机 知乎 编辑:程序博客网 时间:2024/05/17 02:32

题意:1e5的一棵树,有点权有边权。 1e5次操作,每次操作询问离点u边距不超过r的最大点权的点的编号是多少,如果多个最小输出最小编号的那个。

思路:开始想是不是树剖分啊,后来感觉不太靠谱,然后就搜了一发,也没发现有什么靠谱的解法。

后来看到昂神的的几句题解,怒敲一发点分治。开始以为不太好写,后来发现其实还好。

离线的做法(在线的没想到怎么写), 复杂度O((n+m)log^2 (n))。 对于一个分治点,搜索出有关的询问,这里每个把每条路径用分治重心拆成两半,像所有的点分治一样,这里会有一个同一颗子树的问题,然后这里并没有什么关系的,证明就是,假设两个点在一颗子树里,接下来的分治仍然会更新这对点,直到不在一颗子树为止,并且答案只会更精确。 对于每一次自问题处理就是分治内的点按照离分治重心的距离排序,再预处理出一个最大前缀数组,显然有单调性啊,所以可以对于每个询问就可以二分处理了。


#include <cstdio>#include <vector>#include <utility>#include <cstring>#include <iostream>#include <algorithm>const int maxn = 100007;const int INF  = 1 << 30;bool vis[maxn], isQ[maxn];int size[maxn], head[maxn], maxe[maxn], ans[maxn], fin[maxn];int val[maxn], pre[maxn], deep[maxn], E_cnt, n, m;struct Node{int w, id;Node() { }Node(int w, int id):w(w), id(id) {   }bool operator < (const Node &x) const { return w < x.w; }};std::vector<Node> dis;std::vector<std::pair<int, int> > ques[maxn];struct Edge{int v, w, next;Edge() { }Edge(int v, int w, int next):v(v), w(w), next(next) { }}edges[maxn * 3];void init(){E_cnt = 0;memset(head, -1, sizeof(head));memset(vis,  0, sizeof(vis));}void addEdge(int u, int v, long long w){edges[E_cnt] = Edge(v, w, head[u]); head[u] = E_cnt ++;edges[E_cnt] = Edge(u, w, head[v]); head[v] = E_cnt ++;}void getSize(int u, int par){size[u] = 1;maxe[u] = 0;for(int i = head[u]; ~i; i = edges[i].next) {int v = edges[i].v;if(v == par || vis[v]) continue;getSize(v, u);size[u] += size[v];maxe[u] = std::max(maxe[u], size[v]);}}int min_node, root;void getRoot(int u, int par, int r){maxe[u] = std::max(maxe[u], size[r] - size[u]);if(min_node > maxe[u]) {min_node = maxe[u], root = u;}for(int i = head[u]; ~i; i = edges[i].next) {int v = edges[i].v;if(v == par || vis[v]) continue;getRoot(v, u, r);}}void getDis(int u, int par, int dep, std::vector<int> & vec){deep[u] = dep;dis.push_back(Node(dep, u));if(isQ[u]) vec.push_back(u);for(int i = head[u]; ~i; i = edges[i].next) {int v = edges[i].v;if(v == par || vis[v]) continue;getDis(v, u, dep + edges[i].w, vec);}}void cal(int root){dis.clear();std::vector<int> vec;getDis(root, root, 0, vec);std::sort(dis.begin(), dis.end());int index = 0;for(int i = 0; i < dis.size(); i ++) {int now = dis[i].id;if(val[index] < val[now]) index = now;else if(val[index] == val[now] && now < index) index = now;pre[i] = index;}for(int i = 0; i < vec.size(); i ++) {int u = vec[i];for(int j = 0; j < ques[u].size(); j ++) {int w = ques[u][j].first - deep[u];int k = std::upper_bound(dis.begin(), dis.end(), Node(w, 0)) - dis.begin() - 1;if(k < 0) continue;int x = ques[u][j].second;int id = ans[x];if(val[id] < val[pre[k]]) ans[x] = pre[k];else if(val[id] == val[pre[k]] && id > pre[k]) ans[x] = pre[k];}}}void divid(int u){min_node = INF;getSize(u,  u);getRoot(u, u, u);cal(root);vis[root] = true;for(int i = head[root]; ~i; i = edges[i].next) {int v = edges[i].v;if(vis[v]) continue;divid(v);}}int main(){init();scanf("%d", &n);for(int i = 1; i <= n; i ++) {scanf("%d", &val[i]);}int u, v, w;for(int i = 1; i < n;  i ++) {scanf("%d %d %d", &u,&v,&w);addEdge(u, v, w);}scanf("%d", &m);val[0] = -1;for(int i = 1; i <= m; i ++) {scanf("%d %d", &u,&w);isQ[u] = true;ans[i] = 0;ques[u].push_back(std::make_pair(w, i));}divid(1);for(int i = 1; i <= m; i ++) {printf("%d\n", ans[i]);}}


0 0