[hihoCoder#1381]Little Y's Tree

试题描述

小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行,每行一个整数表示询问的答案。

输入示例


输出示例


数据规模及约定

见“输入

题解

我们将每次删除的所有边的深度较大的节点作为关键点,建立虚树。然后我们发现我们可以维护一下区间的连通性,将所有节点按照 dfs 序从小到大排序以后,用线段树合并连通信息。对于两个连通块 A 和 B,若 A 的直径为 (a, b),B 的直径为 (c, d),那么 A U B 的直径就是 (a, b), (c, d), (a, c), (a, d), (b, c), (b, d) 六种情况,我们取一个最大值即可。对于一颗虚树,我们按照深度从大到小依次查询该节点对应区间的连通块直径,累计答案,再将这个区间打上删除标记,最后记得要恢复删除标记。

对了,这题要 O(1) 求 LCA。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 100010
#define maxm 200010
#define maxlog 20
#define oo 2147483647
#define LL long long
int n, m, head[maxn], Next[maxm], To[maxm], dist[maxm];
struct Edge {
int a, b, c;
Edge() {}
Edge(int _1, int _2, int _3): a(_1), b(_2), c(_3) {}
} es[maxn]; void AddEdge(int a, int b, int c) {
To[++m] = b; dist[m] = c; Next[m] = head[a]; head[a] = m;
swap(a, b);
To[++m] = b; dist[m] = c; Next[m] = head[a]; head[a] = m;
return ;
} int dep[maxn], list[maxm], cl, pos[maxn], ord[maxn], clo, ordr[maxn], Pos[maxn];
LL Dep[maxn];
void build(int u, int fa) {
list[++cl] = u; pos[u] = cl; ord[u] = ++clo; Pos[clo] = u;
for(int e = head[u]; e; e = Next[e]) if(To[e] != fa) {
dep[To[e]] = dep[u] + 1;
Dep[To[e]] = Dep[u] + dist[e];
build(To[e], u);
list[++cl] = u;
}
ordr[u] = clo;
return ;
}
int Lca[maxlog][maxm], Log[maxm];
void rmq_init() {
Log[1] = 0;
for(int i = 2; i <= cl; i++) Log[i] = Log[i>>1] + 1;
for(int i = 1; i <= cl; i++) Lca[0][i] = list[i];
for(int j = 1; (1 << j) <= cl; j++)
for(int i = 1; i + (1 << j) - 1 <= cl; i++) {
int a = Lca[j-1][i], b = Lca[j-1][i+(1<<j-1)];
if(dep[a] < dep[b]) Lca[j][i] = a;
else Lca[j][i] = b;
}
return ;
}
int lca(int a, int b) {
int l = min(pos[a], pos[b]), r = max(pos[a], pos[b]);
int t = Log[r-l+1];
a = Lca[t][l]; b = Lca[t][r-(1<<t)+1];
return dep[a] < dep[b] ? a : b;
}
LL calc(int a, int b) {
return Dep[a] + Dep[b] - (Dep[lca(a,b)] << 1);
} struct Node {
bool hasv;
int A, B; LL Len;
Node() {}
Node(int _1, int _2, LL _3, bool _4): A(_1), B(_2), Len(_3), hasv(_4) {}
} ns[maxn<<2];
void maintain(Node& o, Node lc, Node rc) {
o.Len = -1;
if(!lc.hasv && !rc.hasv){ o.Len = o.hasv = 0; return ; }
if(!lc.hasv) {
o = rc;
return ;
}
if(!rc.hasv) {
o = lc;
return ;
}
o.hasv = 1;
if(o.Len < lc.Len) o.Len = lc.Len, o.A = lc.A, o.B = lc.B;
if(o.Len < rc.Len) o.Len = rc.Len, o.A = rc.A, o.B = rc.B;
LL d = calc(lc.A, rc.A);
if(o.Len < d) o.Len = d, o.A = lc.A, o.B = rc.A;
d = calc(lc.A, rc.B);
if(o.Len < d) o.Len = d, o.A = lc.A, o.B = rc.B;
d = calc(lc.B, rc.A);
if(o.Len < d) o.Len = d, o.A = lc.B, o.B = rc.A;
d = calc(lc.B, rc.B);
if(o.Len < d) o.Len = d, o.A = lc.B, o.B = rc.B;
return ;
}
void build(int L, int R, int o) {
if(L == R) ns[o] = Node(Pos[L], Pos[R], 0, 1);
else {
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
build(L, M, lc); build(M+1, R, rc);
maintain(ns[o], ns[lc], ns[rc]);
ns[o].hasv = 1;
}
// printf("seg[%d, %d]: %d %d %lld\n", L, R, ns[o].A, ns[o].B, ns[o].Len);
return ;
}
void update(int L, int R, int o, int ql, int qr, bool v) {
if(ql <= L && R <= qr) ns[o].hasv = v;
else {
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(ql <= M) update(L, M, lc, ql, qr, v);
if(qr > M) update(M+1, R, rc, ql, qr, v);
maintain(ns[o], ns[lc], ns[rc]);
}
return ;
}
Node query(int L, int R, int o, int ql, int qr) {
if(ql <= L && R <= qr) return ns[o];
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
Node ans(-1, -1, -1, 0);
if(ql <= M) {
Node tmp = query(L, M, lc, ql, qr), tt(0, 0, -1, 1);
maintain(tt, tmp, ans);
if(tmp.hasv) ans = tt;
}
if(qr > M) {
Node tmp = query(M+1, R, rc, ql, qr), tt(0, 0, -1, 1);
maintain(tt, tmp, ans);
if(tmp.hasv) ans = tt;
}
// printf("[%d, %d] %d %d %d %lld(%d)\nans: %lld\n", L, R, o, ql, qr, ns[o].Len, ns[o].hasv, ans.Len);
return ans;
} bool cmp(int a, int b) { return pos[a] < pos[b]; }
int psi[maxn], cpi, ps[maxn], cp, vis[maxn];
bool flg[maxn]; struct Vtree {
int m, head[maxn], Next[maxm], To[maxm];
LL dist[maxm], ans;
void init() {
ans = m = 0;
return ;
}
void AddEdge(int a, int b, LL c) {
// printf("Add2: %d %d %lld\n", a, b, c);
To[++m] = b; dist[m] = c; Next[m] = head[a]; head[a] = m;
swap(a, b);
To[++m] = b; dist[m] = c; Next[m] = head[a]; head[a] = m;
return ;
}
void dfs(int u, int fa) {
for(int e = head[u]; e; e = Next[e]) if(To[e] != fa)
dfs(To[e], u);
if(flg[u]) {
Node tmp = query(1, n, 1, ord[u], ordr[u]); flg[u] = 0;
if(tmp.hasv) ans += tmp.Len;
// printf("at %d tmp: %lld [%d, %d]\n", u, tmp.Len, ord[u], ordr[u]);
update(1, n, 1, ord[u], ordr[u], 0);
}
return ;
}
void dfs2(int u, int fa) {
for(int e = head[u]; e; e = Next[e]) if(To[e] != fa)
dfs2(To[e], u);
update(1, n, 1, ord[u], ordr[u], 1);
head[u] = 0;
return ;
}
} vt; int main() {
n = read();
for(int i = 1; i < n; i++) {
int a = read(), b = read(), c = read();
AddEdge(a, b, c);
es[i] = Edge(a, b, c);
}
build(1, 0);
rmq_init();
// for(int i = 1; i <= cl; i++) printf("%d%c", Lca[0][i], i < cl ? ' ' : '\n');
// for(int i = 1; i <= n; i++) printf("%d%c", pos[i], i < n ? ' ' : '\n');
build(1, n, 1);
int q = read();
// for(int i = 1; i <= n; i++) printf("%d%c", ord[i], i < n ? ' ' : '\n');
while(q--) {
int cpi = read(); cp = 0;
for(int i = 1; i <= cpi; i++) {
int e = read(), u = dep[es[e].a] < dep[es[e].b] ? es[e].b : es[e].a;
ps[++cp] = psi[i] = u;
vis[ps[cp]] = q + 1;
flg[ps[cp]] = 1;
}
if(vis[1] != q + 1) ps[++cp] = 1, flg[1] = 1;
sort(psi + 1, psi + cpi + 1, cmp);
for(int i = 1; i < cpi; i++) {
int c = lca(psi[i], psi[i+1]);
if(vis[c] != q + 1) vis[c] = q + 1, ps[++cp] = c;
}
sort(ps + 1, ps + cp + 1, cmp);
vt.init();
for(int i = 1; i < cp; i++) {
int a = ps[i], b = ps[i+1], c = lca(a, b);
vt.AddEdge(b, c, Dep[b] - Dep[c]);
}
vt.dfs(1, 0);
vt.dfs2(1, 0);
printf("%lld\n", vt.ans);
} return 0;
}

[hihoCoder#1381]Little Y's Tree的更多相关文章

  1. DFS序+线段树 hihoCoder 1381 Little Y's Tree(树的连通块的直径和)

    题目链接 #1381 : Little Y's Tree 时间限制:24000ms 单点时限:4000ms 内存限制:512MB 描述 小Y有一棵n个节点的树,每条边都有正的边权. 小J有q个询问,每 ...

  2. hihoCoder1381 - Little Y's Tree

    Portal Description 给出一个\(n(n\leq10^5)\)个点的带边权的树.进行\(Q\)次询问:每次删除树上的\(k\)条边,求剩下的\(k+1\)个连通块中最远点对距离的和.\ ...

  3. hihoCoder挑战赛23

    hihoCoder挑战赛23 A.Emulator 题意 给一张图,有\(N(N \le 300)\)个点, 给出任意两点之间的最短路. 求最多可以去掉多少条边,使得任意两点的最短路长度不变. 思路 ...

  4. Size Balance Tree(SBT模板整理)

    /* * tree[x].left 表示以 x 为节点的左儿子 * tree[x].right 表示以 x 为节点的右儿子 * tree[x].size 表示以 x 为根的节点的个数(大小) */ s ...

  5. HDU3333 Turing Tree(线段树)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=3333 Description After inventing Turing Tree, 3x ...

  6. Codeforces 620E New Year Tree(DFS序 + 线段树)

    题目大概说给一棵树,树上结点都有颜色(1到60),进行下面两个操作:把某结点为根的子树染成某一颜色.询问某结点为根的子树有多少种颜色. 子树,显然DFS序,把子树结点映射到连续的区间.而注意到颜色60 ...

  7. Linux/Ubuntu tree 命令以树形结构显示文件夹目录结构

    1.安装命令工具 sudo apt-get -y install tree 2.可以查看关于tree命令的帮助信息 $ tree --help usage: tree [-adfghilnpqrstu ...

  8. POJ3321 Apple Tree(DFS序)

    题目,是对一颗树,单点修改.子树查询.典型的dfs序入门题. DFS序可以将一颗树与子树们表示为一个连续的区间,然后用线段树来维护:感觉算是树链剖分的一种吧,和轻重链剖分不同的是这是对子树进行剖分的. ...

  9. Bzoj 2588: Spoj 10628. Count on a tree 主席树,离散化,可持久,倍增LCA

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2588 2588: Spoj 10628. Count on a tree Time Limit ...

随机推荐

  1. SVN Access to ‘/svn/Test/!svn/me’ forbidden,不能更新解决办法

    今天上班,使用公司配置的电脑进行项目的更新.SVN报如下错误, SVN Access to '/svn/Test/!svn/me' forbidden,不能更新解决办法 很有意思: 开始以为自己的SV ...

  2. php 设计模式 例子

    加载类:include("./Ren.class.php");include "./Ren.class.php"; require("./Ren.cl ...

  3. PHP实现观察者模式

    <?php //php设计模式观察者模式 /** 被观察者 */ class user implements SplSubject{ public $lognum; public $hobby; ...

  4. RGB to HSI, HSI to RGB Conversion Calculator

    The RGB color model is an additive system in which each color is defined by the amount of red, green ...

  5. 谈谈我对PhoneGap的看法——(摘自唐巧的技术博客)

    源地址:http://blog.devtang.com/blog/2012/03/24/talk-about-uiwebview-and-phonegap/ 主题部分 我认为PhoneGap有以下3大 ...

  6. 无法访问 IIS 元数据库。您没有足够的特权访问计算机上的 IIS 网站

    我是WIN10+VS2015  之前用的是VS2012     后来卸载了VS2012 就出现了这个错误,请问该如何解决 在VS的图标上 按右键用管理员(Administrator)运行

  7. Python 线程、进程和协程

    python提供了两个模块来实现多线程thread 和threading ,thread 有一些缺点,在threading 得到了弥补,为了不浪费时间,所以我们直接学习threading 就可以了. ...

  8. CSS核心的几个概念

    盒模型.position.float.他们是css的基础,之间看似独立却又相辅相成. 元素类型 块级元素.内联元素 他们之间有以下区别: 1.块级元素独占一行,除非显示的修改display属性.而内联 ...

  9. php函数mt_rand和rand 速度测试

    今天在写代码时,看到以前的同时写了一个取随机数,用到了mt_rand(2,19) 就顺手搜了一下,mt_rand和rand的区别. 先看官方的解释 mt_rand 和 rand mt_rand — 生 ...

  10. MYSQL 连接数据库命令收藏

    一.MySQL 连接本地数据库,用户名为“root”,密码“123”(注意:“-p”和“123” 之间不能有空格) C:\>mysql -h localhost -u root -p123 二. ...