题目链接

#1381 : Little Y's Tree

时间限制:24000ms
单点时限:4000ms
内存限制:512MB

描述

小Y有一棵n个节点的树,每条边都有正的边权。

小J有q个询问,每次小J会删掉这个树中的k条边,这棵树被分成k+1个连通块。小J想知道每个连通块中最远点对距离的和。

这里的询问是互相独立的,即每次都是在小Y的原树上进行操作。

输入

第一行一个整数n,接下来n-1行每行三个整数u,v,w,其中第i行表示第i条边边权为wi,连接了ui,vi两点。

接下来一行一个整数q,表示有q组询问。

对于每组询问,第一行一个正整数k,接下来一行k个不同的1到n-1之间的整数,表示删除的边的编号。

1<=n,q,Σk<=105, 1<=w<=109

输出

共q行,每行一个整数表示询问的答案。

题解:

  首先考虑给出两个点集,如何求这两个点集合并之后的直径,方法是把两个点集的直径分别求出来,然后对于这4个点,求出两两之间距离的最大值。

  于是可以按dfs序建立线段树,然后求出每个区间的直径。

  而对于一个询问,删掉k条边,每棵子树都对应的dfs序中的若干区间,而且区间总个数不会超过2k,对于每个区间可以在线段树中查询。

  时间复杂度O(nlog^2n)。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e5 + 5;
const int D = 20; struct Edge {
int u, v, w;
}; int L[N], R[N], p[N], rt[N][D], dep[N];
ll d[N];
int dfs_clock;
vector<Edge> edges;
vector<int> id[N];
int n, m; void init_edge() {
edges.clear();
for (int i=1; i<=n; ++i) id[i].clear();
m = 0;
} void add_edge(int u, int v, int w) {
edges.push_back((Edge){u, v, w});
m = edges.size();
id[u].push_back(m-1);
} void DFS(int u, int fa) {
L[u] = ++dfs_clock;
p[dfs_clock] = u;
dep[u] = dep[fa] + 1;
rt[u][0] = fa;
for (int i: id[u]) {
Edge &e = edges[i];
if (e.v == fa) continue;
d[e.v] = d[u] + e.w;
DFS(e.v, u);
}
R[u] = dfs_clock;
} void init_LCA() {
for (int j=1; j<D; ++j) {
for (int i=1; i<=n; ++i) {
rt[i][j] = rt[rt[i][j-1]][j-1];
}
}
} int LCA(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
for (int i=0; i<D; ++i) {
if ((dep[u]-dep[v]) >> i & 1) u = rt[u][i];
}
if (u == v) return u;
for (int i=D-1; i>=0; --i) {
if (rt[u][i] != rt[v][i]) {
u = rt[u][i];
v = rt[v][i];
}
}
return rt[u][0];
} ll dis(int u, int v) {
return d[u] + d[v] - 2 * d[LCA(u, v)];
} struct Node {
ll d;
int a, b;
Node(ll d=0, int a=0, int b=0) : d(d), a(a), b(b) {}
bool operator < (const Node &rhs) const {
return d < rhs.d;
}
}; Node nd[N<<2]; Node better(Node x, Node y) {
if (x.d == -1) return y;
if (y.d == -1) return x;
Node z1 = Node(dis(x.a, y.a), x.a, y.a);
Node z2 = Node(dis(x.a, y.b), x.a, y.b);
Node z3 = Node(dis(x.b, y.a), x.b, y.a);
Node z4 = Node(dis(x.b, y.b), x.b, y.b);
return max({x, y, z1, z2, z3, z4});
} #define lch o << 1
#define rch o << 1 | 1 void build(int o, int l, int r) {
if (l == r) {
nd[o] = Node(0, p[l], p[l]);
return ;
}
int mid = l + r >> 1;
build(lch, l, mid);
build(rch, mid+1, r);
nd[o] = better(nd[lch], nd[rch]);
} Node query(int o, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return nd[o];
}
int mid = l + r >> 1;
Node ret = Node(-1, 0, 0);
if (ql <= mid) ret = better(ret, query(lch, l, mid, ql, qr));
if (qr > mid) ret = better(ret, query(rch, mid+1, r, ql, qr));
return ret;
} bool cmp(int a, int b) {
return L[a] < L[b];
} int x[N], s[N];
vector<int> edge[N];
ll ans; void prepare() {
dfs_clock = 0;
dep[0] = 0;
d[1] = 0; DFS(1, 0);
init_LCA();
build(1, 1, n);
} void DFS(int u) {
Node res = Node(-1, x[u], x[u]);
int ql = L[x[u]], qr = R[x[u]];
for (int v: edge[u]) {
DFS(v);
res = better(res, query(1, 1, n, ql, L[x[v]]-1));
ql = R[x[v]] + 1;
}
res = better(res, query(1, 1, n, ql, qr));
ans += res.d;
} int main() {
scanf("%d", &n);
init_edge();
for (int i=1; i<n; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w);
add_edge(v, u, w);
} prepare(); int q, k;
scanf("%d", &q);
while (q--) {
scanf("%d", &k);
int idx;
for (int i=1; i<=k; ++i) {
scanf("%d", &idx);
idx--;
Edge &e = edges[idx*2];
if (dep[e.u] > dep[e.v]) x[i] = e.u;
else x[i] = e.v;
}
sort(x+1, x+1+k, cmp); x[0] = 1;
int nn = 1;
s[nn] = 0;
for (int i=0; i<=k; ++i) edge[i].clear();
//s[nn]:0~k, x[s[n]]:1 or x[1~k]
for (int i=1; i<=k; ++i) {
while (!(L[x[s[nn]]] <= L[x[i]] && R[x[i]] <= R[x[s[nn]]])) nn--;
edge[s[nn]].push_back(i);
s[++nn] = i;
} ans = 0;
DFS(0);
printf("%lld\n", ans);
}
return 0;
}

DFS序+线段树 hihoCoder 1381 Little Y's Tree(树的连通块的直径和)的更多相关文章

  1. [hihoCoder#1381]Little Y's Tree

    [hihoCoder#1381]Little Y's Tree 试题描述 小Y有一棵n个节点的树,每条边都有正的边权. 小J有q个询问,每次小J会删掉这个树中的k条边,这棵树被分成k+1个连通块.小J ...

  2. 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] D ...

  3. Codeforces 343D Water Tree(DFS序 + 线段树)

    题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...

  4. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  5. HDU 3974 Assign the task (DFS序 + 线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3974 给你T组数据,n个节点,n-1对关系,右边的是左边的父节点,所有的值初始化为-1,然后给你q个操 ...

  6. 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

    题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...

  7. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  8. BZOJ1103 [POI2007]大都市meg dfs序 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1103 题意概括 一棵树上,一开始所有的边权值为1,我们要支持两种操作: 1. 修改某一条边的权值为 ...

  9. Codeforces Round #442 (Div. 2)A,B,C,D,E(STL,dp,贪心,bfs,dfs序+线段树)

    A. Alex and broken contest time limit per test 2 seconds memory limit per test 256 megabytes input s ...

随机推荐

  1. Codility NumberSolitaire Solution

    1.题目: A game for one player is played on a board consisting of N consecutive squares, numbered from ...

  2. windows安装zookeeper-单机模式

    zookeeper下载地址:http://zookeeper.apache.org/releases.html#download   本次使用的是3.4.9版本 前提:请安装JDK 安装: 创建安装目 ...

  3. Django模型的Field Types总结

    转:http://blog.csdn.net/devil_2009/article/details/41735611 Field Types 常用参数: null 如果设置为 True , Djang ...

  4. 数据库 'xxx 的事务日志已满。若要查明无法重用日志中的空间的原因,请参阅 sys.databases 中的 log_reuse_wait_desc 列。

    ---清空日志: USE [master] GO ALTER DATABASE cits SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE cits ...

  5. 为什么要用base64编码

    1.需求 了解为什么要使用base64对数据编码 2.理由 因为传输二进制数据的时候,网络中间的有些路由会把ascii码中的不可见字符删了,导致数据不一致.一般也会对url进行base64编码 Whe ...

  6. 6 VC维

    1 VC维的定义 VC维其实就是第一个break point的之前的样本容量.标准定义是:对一个假设空间,如果存在N个样本能够被假设空间中的h按所有可能的2的N次方种形式分开,则称该假设空间能够把N个 ...

  7. 高性能MySQL(二):创建高性能索引

    ) not null); insert into city_demo(city) select city from city insert into city_demo(city) select ci ...

  8. 【NodeJs环境下bower】如何更改bower_components文件夹的位置

    bower在初始化,默认是将bower_components文件夹放到项目的根目录下,若是public/index.html如何配置bower_components下的js或者css类库呢?只需要将b ...

  9. centos 安装pip,使用pip安装django

    python版本要2.7.x以上版本,若未安装python执行以下命令安装: wget https://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz ...

  10. iOS url中文编码

    有两种方法: 一,使用NSString的方法: NSString* string2 = [string1 stringByAddingPercentEscapesUsingEncoding:NSUTF ...