首先我们要时光倒流, 倒着做, 变成加边操作维护关键边. 先随意搞出一颗树, 树上每条边都是关键边(因为是树, 去掉就不连通了)....然后加边(u, v)时, 路径(u, v)上的所有边都变成非关键边了, 因为形成了环, 环上任意2点有2条路径。。。下图, 加上蓝色的边, 红色x的边就变成了非关键边.

所以树链剖分维护一下...时间复杂度O(NlogN+MlogM+Qlog^2N), 可以AC.

翻了翻ZY的标解:“动态维护树+最近公共祖先查询”....复杂度是O(NlogN+M+QlogN)的.比我不知道高到那里去.....不过他的解法太神了orz(其实是懒得看= =

----------------------------------------------------------------------------------------

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
typedef pair<int, int> pii;
 
const int maxn = 30009;
const int maxM = 100009;
const int maxQ = 40009;
 
int par[maxn], F[maxM], ans[maxQ];
int M, N, qn, n, L, R;
int fa[maxn], ch[maxn], top[maxn], sz[maxn], dep[maxn], Id[maxn], TOP;
 
inline int getint() {
char c = getchar();
for(; !isdigit(c); c = getchar())
if(c == '-') return  -1;
int ret = 0;
for(; isdigit(c); c = getchar())
ret = ret * 10 + c - '0';
return ret;
}
 
struct Q {
int t, u, v;
} q[maxQ];
 
struct E {
int u, v;
E() {}
E(int _u, int _v) : u(_u), v(_v) {
}
bool operator < (const E &p) const {
return u < p.u || (u == p.u && v < p.v);
}
} e[maxM];
 
struct edge {
int t;
edge* n;
} EDGE[maxn << 1], *Pt = EDGE, *H[maxn];
 
inline void AddEdge(int u, int v) {
Pt->t = v, Pt->n = H[u], H[u] = Pt++;
}
 
int Find(int x) {
return x == par[x] ? x : par[x] = Find(par[x]);
}
 
void dfs(int x) {
sz[x] = 1, ch[x] = -1;
for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) {
fa[e->t] = x;
dep[e->t] = dep[x] + 1;
dfs(e->t);
sz[x] += sz[e->t];
if(!~ch[x] || sz[ch[x]] < sz[e->t]) ch[x] = e->t;
}
}
 
void DFS(int x) {
top[x] = TOP;
Id[x] = ++n;
if(~ch[x]) DFS(ch[x]);
for(edge* e = H[x]; e; e = e->n)
if(e->t != fa[x] && e->t != ch[x]) DFS(TOP = e->t);
}
 
struct Node {
Node *lc, *rc;
int v, t;
inline void upd() {
if(t) {
v = 0;
} else if(lc)
v = lc->v + rc->v;
}
inline void pd() {
if(t && lc) {
lc->t = rc->t = 1;
t = 0;
}
}
} pool[maxn << 1], *pt = pool, *Root;
 
void Build(Node* t, int l, int r) {
t->v = r - l + 1;
t->t = 0;
if(l != r) {
int m = (l + r) >> 1;
Build(t->lc = pt++, l, m);
Build(t->rc = pt++, m + 1, r);
} else
t->lc = t->rc = NULL;
}
 
void Change(Node* t, int l, int r) {
if(!t->v) return;
if(L <= l && r <= R) {
t->t = 1;
} else {
int m = (l + r) >> 1;
if(L <= m) Change(t->lc, l, m);
if(m < R) Change(t->rc, m + 1, r);
}
t->upd();
}
 
int Sum(Node* t, int l, int r) {
if(L <= l && r <= R)
return t->v;
int m = (l + r) >> 1;
t->pd(), t->lc->upd(), t->rc->upd();
return (L <= m ? Sum(t->lc, l, m) : 0) + (m < R ? Sum(t->rc, m + 1, r) : 0);
}
 
void Modify(int u, int v) {
for(; top[u] != top[v]; u = fa[top[u]]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
L = Id[top[u]], R = Id[u];
Change(Root, 1, N);
}
if(u == v) return;
if(dep[u] > dep[v]) swap(u, v);
L = Id[u] + 1, R = Id[v];
Change(Root, 1, N);
}
 
int Query(int u, int v) {
int ret = 0;
for(; top[u] != top[v]; u = fa[top[u]]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
L = Id[top[u]], R = Id[u];
ret += Sum(Root, 1, N);
}
if(dep[u] > dep[v]) swap(u, v);
L = Id[u] + 1, R = Id[v];
return ret + Sum(Root, 1, N);
}
 
void Work() {
for(int i = 0; i < N; i++) par[i] = i;
for(int i = 0; i < M; i++) if(F[i]) {
int u = Find(e[i].u), v = Find(e[i].v);
if(u != v) {
AddEdge(e[i].u, e[i].v);
AddEdge(e[i].v, e[i].u);
par[u] = v;
} else
F[i] = -1;
}
fa[0] = -1, dep[0] = 0, dfs(0);
DFS(TOP = 0);
Build(Root = pt++, 1, N);
for(int i = 0; i < M; i++)
if(!~F[i]) Modify(e[i].u, e[i].v);
for(int i = qn; i--; ) if(q[i].t) {
ans[i] = Query(q[i].u, q[i].v);
} else
Modify(q[i].u, q[i].v);
for(int i = 0; i < qn; i++)
if(q[i].t) printf("%d\n", ans[i]);
}
 
void Init() {
N = getint(), M = getint();
for(int i = 0; i < M; i++) {
e[i].u = getint() - 1, e[i].v = getint() - 1;
if(e[i].u > e[i].v) swap(e[i].u, e[i].v);
F[i] = 1;
}
sort(e, e + M);
qn = 0;
while((q[qn].t = getint()) != -1) {
q[qn].u = getint() - 1, q[qn].v = getint() - 1;
if(q[qn].u > q[qn].v) swap(q[qn].u, q[qn].v);
if(!q[qn].t) {
F[lower_bound(e, e + M, E(q[qn].u, q[qn].v)) - e] = 0;
}
qn++;
}
}
 
int main() {
Init();
Work();
return 0;
}

----------------------------------------------------------------------------------------

1969: [Ahoi2005]LANE 航线规划

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 180  Solved: 87
[Submit][Status][Discuss]

Description

对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系。 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1、2、3……。 一些先遣飞船已经出发,在星球之间开辟探险航线。 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线。 例如下图所示:  在5个星球之间,有5条探险航线。 A、B两星球之间,如果某条航线不存在,就无法从A星球抵达B星球,我们则称这条航线为关键航线。 显然上图中,1号与5号星球之间的关键航线有1条:即为4-5航线。 然而,在宇宙中一些未知的磁暴和行星的冲撞,使得已有的某些航线被破坏,随着越来越多的航线被破坏,探险飞船又不能及时回复这些航线,可见两个星球之间的关键航线会越来越多。 假设在上图中,航线4-2(从4号星球到2号星球)被破坏。此时,1号与5号星球之间的关键航线就有3条:1-3,3-4,4-5。 小联的任务是,不断关注航线被破坏的情况,并随时给出两个星球之间的关键航线数目。现在请你帮助完成。

Input

第一行有两个整数N,M。表示有N个星球(1< N < 30000),初始时已经有M条航线(1 < M < 100000)。随后有M行,每行有两个不相同的整数A、B表示在星球A与B之间存在一条航线。接下来每行有三个整数C、A、B。C为1表示询问当前星球A和星球B之间有多少条关键航线;C为0表示在星球A和星球B之间的航线被破坏,当后面再遇到C为1的情况时,表示询问航线被破坏后,关键路径的情况,且航线破坏后不可恢复; C为-1表示输入文件结束,这时该行没有A,B的值。被破坏的航线数目与询问的次数总和不超过40000。

Output

对每个C为1的询问,输出一行一个整数表示关键航线数目。 注意:我们保证无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。

Sample Input

5 5
1 2
1 3
3 4
4 5
4 2
1 1 5
0 4 2
1 5 1
-1

Sample Output

1
3

HINT

Source

BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )的更多相关文章

  1. BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]

    题意: 一张图,删除边,求两点之间的割边数量.保证任意时刻图连通 任求一棵生成树,只有树边可能是割边 时间倒流,加入一条边,就是两点路径上的边都不可能是割边,区间覆盖... 然后本题需要把边哈希一下, ...

  2. 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

  3. bzoj1969 [Ahoi2005]LANE 航线规划 树链剖分

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1969 题解 如果我们把整个图边双联通地缩点,那么最终会形成一棵树的样子. 那么在这棵树上,\( ...

  4. ●BZOJ 1969 [Ahoi2005]LANE 航线规划

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1969 题解: 线段树,树链剖分,反向考虑思路是很巧妙,但是感觉代码真的恶心.. 反着考虑,先 ...

  5. 【刷题】BZOJ 1969 [Ahoi2005]LANE 航线规划

    Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系--一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel ...

  6. 【BZOJ 1969】 1969: [Ahoi2005]LANE 航线规划 (树链剖分+线段树)

    1969: [Ahoi2005]LANE 航线规划 Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星 ...

  7. 【BZOJ】1969: [Ahoi2005]LANE 航线规划

    题目链接: 传送~~ 题解:  老夫实在是码不动了…… 正着搞显然不好做,尝试倒着乱搞.先给被删除的边标记一个时间戳,先删除的时间戳大,同时维护询问时间戳,询问早的时间戳大.没被删除过的边时间戳都是0 ...

  8. 洛谷 P2542 [AHOI2005]航线规划 树链剖分_线段树_时光倒流_离线

    Code: #include <map> #include <cstdio> #include <algorithm> #include <cstring&g ...

  9. luogu2542 航线规划 (树链剖分)

    不会lct,所以只能树剖乱搞 一般这种删边的题都是离线倒着做,变成加边 他要求的结果其实就是缩点以后两点间的距离. 然后先根据最后剩下的边随便做出一个生成树,然后假装把剩下的边当成加边操作以后处理 这 ...

随机推荐

  1. magento 获取attribute的所有option

    $attribute = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'color');if ($attr ...

  2. UNIX网络编程--读书笔记

    会集中这段时间写UNIX网络编程这本书的读书笔记,准备读三本,这一系类的文章会不断更新,一直会持续一个月多,每篇的前半部分是书中讲述的内容,每篇文章的后半部分是自己的心得体会,文章中的红色内容是很重要 ...

  3. BZOJ 1024 SCOI 2009 生日快乐 深搜

    题目大意:有一块蛋糕,长为X,宽为Y.如今有n个人来分这块蛋糕,还要保证每一个人分的蛋糕的面积相等.求一种分法,使得全部的蛋糕的长边与短边的比值的最大值最小. 思路:刚拿到这个题并没有什么思路.可是定 ...

  4. localhost和127.0.0.1区别

    详情见: http://blog.csdn.net/xifeijian/article/details/12879395

  5. hadoop 学习

    不同版本间Hadoop拷贝 通过NFS,将hdfs挂在到本地

  6. 更改Oracle数据文件名及数据文件存放路径

    更改Oracle数据文件名及数据文件存放路径 SQL> select * from v$dbfile;        FILE# NAME ---------- ---------------- ...

  7. Linux学习之域名解析命令

    (1) /etc/hosts :记录hostname对应的ip地址 /etc/resolv.conf :设置DNS服务器的ip地址 /etc/host.conf :指定域名解析的顺序(是从本地的hos ...

  8. windows迁移linux问题集锦[ZZ]

    http://blog.csdn.net/m_star_jy_sy/article/details/8482202 1)‘_wcsicmp’在此作用域中尚未声明 #ifdef WIN32#define ...

  9. 说出x的结果,并解释为什么?

    var x = 1; if(function f(){}){ x += typeof f; } x; //x的结果是? x=1undefined 首先是 if表达式的问题 if括号里,不一定非要用== ...

  10. php composer包管理工具

    一 . 包管理工具 你在Centos上装工具的时候直接yum -y install xx 比你去rpm -ivh xx.rpm 是不是爽很多呢? composer 就是安装php 代码的一个类似工具. ...