Annoying problem

Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5296


Mean:

给你一个有根树和一个节点集合S,初始S为空,有q个操作,每个操作要么从树中选一个结点加入到S中(不删除树中节点),要么从S集合中删除一个结点。你需要从树中选一些边组成集合E,E中的边能够是S中的节点连通。对于每一个操作,输出操作后E中所有边的边权之和。

analyse:

首先是构图,把树看作一个无向图,使用邻接表存图。

处理出从1号结点的dfs序存储起来。

添加点u操作:查找S集合中的点与添加的点dfs序在前面且编号最大的点,以及dfs序在后面且编号最小的点,设这两个点是x,y。

那么增加的花费是:dis[u]-dis[lca[(x,u)] - dis [lca(y,u)] + dis[lca(x,y) ]; 其中dis代表该点到根节点的距离。

对于删除点u操作:先把点从集合中删除,然后再计算减少花费,计算公式和增加的计算方法一样。

也是看了题解才撸出来的。

Time complexity: O(N)

Source code: 

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-07-22-11.22
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define LL long long
#define ULL unsigned long long
#define rep(i,n) for(int i=0;i<n;++i)
using namespace std; const int N = 100010,D=20;
int st[N], ori[N], dfs_clock;
vector<pair<int, int> > G[N];
int shortcut[D][N], dep[N];
int *fa;
int get_lca( int a, int b )
{
if( dep[a] < dep[b] )
swap( a, b );
for( int i = D - 1; ~i; --i )
{
if( dep[a] - dep[b] >> i & 1 )
a = shortcut[i][a];
}
if( a == b ) return a;
for( int i = D - 1; ~i; --i )
{
if( shortcut[i][a] != shortcut[i][b] )
{
a = shortcut[i][a];
b = shortcut[i][b];
}
}
return fa[a];
} int dis[N];
void dfs( int u, int father )
{
st[u] = ++dfs_clock;
ori[dfs_clock] = u;
vector<pair<int, int> > :: iterator it;
for( it = G[u].begin(); it != G[u].end(); ++it )
{
int v = ( *it ).first;
int w = ( *it ).second;
if( v == father )continue;
fa[v] = u;
dep[v] = dep[u] + 1;
dis[v] = dis[u] + w;
dfs( v, u );
}
} void prepare( int n )
{
for( int j = 1; j < D; ++j )
{
rep( i, n )
{
int &res = shortcut[j][i];
res = shortcut[j - 1][i];
if( ~res ) res = shortcut[j - 1][res];
}
}
} set<int> nodes;
int get_dis( int a, int b )
{
return dis[a] + dis[b] - 2 * dis[get_lca( a, b )];
} int add( int u )
{
if( !nodes.empty() )
{
set<int>::iterator low, high;
low = nodes.lower_bound( st[u] );
high = low;
if( low == nodes.end() || low == nodes.begin() )
{
low = nodes.begin();
high = nodes.end();
high--;
}
else low--;
int x = ori[*low];
int y = ori[*high];
int res = get_dis( x, u ) + get_dis( y, u ) - get_dis( x, y );
return res;
}
return 0;
} int main()
{
ios_base::sync_with_stdio( false );
cin.tie( 0 );
int T, n, q, u, v, w;
scanf( "%d", &T );
rep( cas, T )
{
scanf( "%d %d", &n, &q );
rep( i, n ) G[i].clear();
dfs_clock = 0;
rep( i, n - 1 )
{
scanf( "%d %d %d", &u, &v, &w );
u--;
v--;
G[u].push_back( make_pair( v, w ) );
G[v].push_back( make_pair( u, w ) );
}
fa = shortcut[0];
fa[0] = -1;
dfs( 0, -1 );
prepare( n );
nodes.clear();
printf( "Case #%d:\n", cas + 1 );
int ans = 0;
while( q-- )
{
int op;
scanf( "%d %d", &op, &u );
u--;
if( op == 1 ) // add
{
if( nodes.find( st[u] ) == nodes.end() )
{
ans += add( u );
nodes.insert( st[u] );
}
}
else // delete
{
if( nodes.find( st[u] ) != nodes.end() )
{
nodes.erase( st[u] );
ans -= add( u );
}
}
printf( "%d\n", ans >> 1 );
}
}
return 0;
}
/* */

  

2015 Multi-University Training Contest 1 - 1009 Annoying problem的更多相关文章

  1. 2015 Multi-University Training Contest 5 1009 MZL's Border

    MZL's Border Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5351 Mean: 给出一个类似斐波那契数列的字符串序列 ...

  2. 2014 Multi-University Training Contest 9#1009

    Just a JokeTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Tot ...

  3. hdu 6394 Tree (2018 Multi-University Training Contest 7 1009) (树分块+倍增)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=6394 思路:用dfs序处理下树,在用分块,我们只需要维护当前这个点要跳出这个块需要的步数和他跳出这个块去 ...

  4. HDU 4608 I-number 2013 Multi-University Training Contest 1 1009题

    题目大意:输入一个数x,求一个对应的y,这个y满足以下条件,第一,y>x,第二,y 的各位数之和能被10整除,第三,求满足前两个条件的最小的y. 解题报告:一个模拟题,比赛的时候确没过,感觉这题 ...

  5. 2015 Multi-University Training Contest 9-1007 Travelling Salesman Problem

    Problem Description Teacher Mai is in a maze with n rows and m columns. There is a non-negative numb ...

  6. ACM多校联赛7 2018 Multi-University Training Contest 7 1009 Tree

    [题意概述] 给一棵以1为根的树,树上的每个节点有一个ai值,代表它可以传送到自己的ai倍祖先,如果不存在则传送出这棵树.现在询问某个节点传送出这棵树需要多少步. [题解] 其实是把“弹飞绵羊”那道题 ...

  7. 2019 Multi-University Training Contest 2 - 1009 - 回文自动机

    http://acm.hdu.edu.cn/showproblem.php?pid=6599 有好几种实现方式,首先都是用回文自动机统计好回文串的个数. 记得把每个节点的cnt加到他的fail上,因为 ...

  8. 2019 Multi-University Training Contest 1 - 1009 - String - 贪心

    不知道错在哪里. 是要把atop改成stop!两个弄混了.感谢自造样例. #include<bits/stdc++.h> using namespace std; typedef long ...

  9. 2015 Multi-University Training Contest 3 hdu 5324 Boring Class

    Boring Class Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

随机推荐

  1. uestc_retarded 模板

    虽然这个队,以后再也没有了,但是他的模板,是永垂不朽的![误 #include <ext/pb_ds/priority_queue.hpp> __gnu_pbds::priority_qu ...

  2. LCLFramework框架之Repository模式

    Respository模式在示例中的实际目的小结一下 Repository模式是架构模式,在设计架构时,才有参考价值: Repository模式主要是封装数据查询和存储逻辑: Repository模式 ...

  3. Win7 32bit + Matlab2013b +Visual Studio 2010联合编程配置

    要建立独立运行的C应用程序,系统中需要安装Matlab.Matlab编译器.C/C++编译器以及Matlab C/C++数学库函数和图形库函数. Matlab编译器使用mbuild命令可以直接将C/C ...

  4. c++算法应用 预备

    章 C + +程序设计 大家好!现在我们将要开始一个穿越" 数据结构.算法和程序" 这个抽象世界的特殊旅程,以解决现实生活中的许多难题.在程序开发过程中通常需要做到如下两点:一是高 ...

  5. [原]quick2.25让描边闪起来

    本文教大家如何使用shader让描边动起来.实质就是间隔一定时间改变描边的颜色.难点:如何通过程序把颜色传给shader.想在quick2.25里面尝试的朋友,参考quick2.25精灵变灰配置一下环 ...

  6. CodeWarrior环境下中断使用

    对于飞思卡尔CodeWarrior的中断使用,一般有3种方法: 1.把#pragma TRAP_PROC放在中断程序前面,并把中断向量表放到*.prm. 例如: #pragma TRAP_PROC v ...

  7. 10个你必须掌握的超酷VI命令技巧

    摘要:大部分Linux开发者对vi命令相当熟悉,可是遗憾的是,大部分开发者都只能掌握一些最常用的Linux vi命令,下面介绍的10个vi命令虽然很多不为人知,但是在实际应用中又能让你大大提高效率. ...

  8. JIT

    http://www.cppblog.com/vczh/category/9583.html

  9. vs.php调试php使用外部的apache进行调试

    vs.php中使用外部的apache进行调试 一般phper们都会有自己配置好的开发调试环境,那么如何在vs.php中使用自己已经配置好的apache+php环境调试 php程序呢?如下: (1)从官 ...

  10. mysql int(1) 与 tinyint(1) 有什么区别?

    From: http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/08/25/2153016.html mysql int(1) tinyint ...