题意

\(N\) 个点 \(M\) 条边的无向图,询问保留图中编号在 \([l,r]\) 的边的时候图中的联通块个数。

\(K\) 次询问强制在线。

\(1\le N,M,K \le 200,000\)

题解

从前往后依次考虑每一条边,如果加入这条边 \(i\) 会生成环,那就删除这个环里最早加入的边 \(j\) ,并且记录下来 \(fout[i] = j\) ,代表 \(i\) 的加入弹掉了 \(j\) 号边 。

也就是说我们动态维护一颗以插入时间为权值的最大生成树,维护这个 \(MST\) 用 \(LCT\) 化边为点的 \(Link, Cut\) 就行了。

然后发现对于一个询问 \([l, r]\) ,就看在 \(l\) 到 \(r\) 之间有多少条边 \(i\) , \(fout[i] < l\) ,然后用 \(n\) 减掉这个数,就是一次询问的答案 。

原因:

如果 \(i\) 边的 \(fout\) 小于 \(l\) ,那么如果只存在 \(l\) 到 \(r\) 的边话, \(i\) 边必定会连接上两个联通块, 答案就要 \(-1\) ;

反之,如果它的 \(fout\) 大于等于 \(l\) ,那么这条边连的是一个联通块里的两个点,不会对答案产生贡献 。

然后对于后面这个区间查 \(<\) 一个数的数有多少个用主席树维护就行了。

注意,自环的 \(fout\) 应该设成 \(\infty\) ,因为它无法减少联通块数量。

ps: 它的强制在线很迷,直接异或就行了。。也不需要交换,以及强制在 \([1, n]\) 之间。。我怀疑没有在线的点。

总结

对于这类区间询问联通块或者一类有关出现次数的题,我们常常可以维护一个 \(Last\) 或者 \(fout\) ,然后查询区间中和这些信息有关的东西,这个又常常使用主席树维护,算是一类套路了吧。

代码

具体实现见代码,写的有点长,但是阅读还是不难。

#include <bits/stdc++.h>

#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define fir first
#define sec second
#define mp make_pair using namespace std; typedef pair<int, int> PII; template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}
template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;} inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("3514.in", "r", stdin);
freopen ("3514.out", "w", stdout);
#endif
} int n, m, k, type; const int N = 2e5 + 1e3; #define ls(o) ch[o][0]
#define rs(o) ch[o][1] template<int Maxn>
struct Link_Cut_Tree { int ch[Maxn][2], fa[Maxn]; inline bool is_root(int o) {
return ls(fa[o]) != o && rs(fa[o]) != o;
} inline bool get(int o) {
return rs(fa[o]) == o;
} PII val[Maxn], minv[Maxn];
inline void push_up(int o) {
minv[o] = min(min(minv[ls(o)], minv[rs(o)]), val[o]);
} inline void rotate(int v) {
int u = fa[v], t = fa[u], d = get(v);
fa[ch[u][d] = ch[v][d ^ 1]] = u;
fa[v] = t; if (!is_root(u)) ch[t][rs(t) == u] = v;
fa[ch[v][d ^ 1] = u] = v;
push_up(u); push_up(v);
} bool rev[Maxn]; inline void Get_Rev(int o) {
rev[o] ^= 1; swap(ls(o), rs(o));
} inline void push_down(int o) {
if (rev[o])
Get_Rev(ls(o)), Get_Rev(rs(o)), rev[o] = false;
} void Push_All(int o) {
if (!is_root(o)) Push_All(fa[o]); push_down(o);
} inline void Splay(int o) {
Push_All(o);
for (; !is_root(o); rotate(o))
if (!is_root(fa[o])) rotate(get(o) != get(fa[o]) ? o : fa[o]);
} inline void Access(int o) {
for (int t = 0; o; o = fa[t = o])
Splay(o), rs(o) = t, push_up(o);
} inline void Make_Root(int o) {
Access(o); Splay(o); Get_Rev(o);
} inline int Find_Root(int o) {
Access(o); Splay(o);
while (ls(o)) o = ls(o), push_down(o);
Splay(o); return o;
} inline void Split(int v, int u) {
Make_Root(v); Access(u); Splay(u);
} inline void Link(int v, int u) {
Split(v, u); fa[v] = u;
} inline void Cut(int v, int u) {
Split(v, u); fa[v] = ls(u) = 0;
} }; Link_Cut_Tree<N << 1> T; int font[N]; template<int Maxn>
struct President_Tree { int ls[Maxn], rs[Maxn], sumv[Maxn], Size; void Update(int &o, int pre, int l, int r, int up) {
o = ++ Size; ls[o] = ls[pre]; rs[o] = rs[pre]; sumv[o] = sumv[pre] + 1;
if (l == r) return ;
int mid = (l + r) >> 1;
if (up <= mid) Update(ls[o], ls[pre], l, mid, up);
else Update(rs[o], rs[pre], mid + 1, r, up);
} int Query(int x, int y, int l, int r, int qr) {
if (r <= qr) return sumv[y] - sumv[x];
int mid = (l + r) >> 1, res = Query(ls[x], ls[y], l, mid, qr);
if (qr > mid) res += Query(rs[x], rs[y], mid + 1, r, qr);
return res;
} }; President_Tree<N * 20> PT; int rt[N]; int main () { File(); n = read(); m = read(); k = read(); type = read(); For (i, 0, n)
T.val[i] = T.minv[i] = mp(m + 1, i); For (i, 1, m) { int node = i + n;
T.val[node] = T.minv[node] = mp(i, node); int u = read(), v = read(); if (u != v) {
T.Make_Root(u);
if (T.Find_Root(v) == u) {
T.Split(u, v); PII p = T.minv[v]; font[i] = p.fir;
T.Cut(u, p.sec); T.Cut(v, p.sec);
}
T.Link(u, node); T.Link(v, node);
} else font[i] = m; PT.Update(rt[i], rt[i - 1], 0, m, font[i]); } int ans = 0;
For (i, 1, k) {
int l = read() ^ (type * ans), r = read() ^ (type * ans);
if (l > r) ans = 0;
else ans = n - PT.Query(rt[l - 1], rt[r], 0, m, l - 1);
printf ("%d\n", ans);
} return 0; }

BZOJ 3514: Codechef MARCH14 GERALD07加强版(LCT + 主席树)的更多相关文章

  1. BZOJ 3514: Codechef MARCH14 GERALD07加强版 [LCT 主席树 kruskal]

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1312  Solved: 501 ...

  2. BZOJ 3514: Codechef MARCH14 GERALD07加强版( LCT + 主席树 )

    从左到右加边, 假如+的边e形成环, 那么记下这个环上最早加入的边_e, 当且仅当询问区间的左端点> _e加入的时间, e对答案有贡献(脑补一下). 然后一开始是N个连通块, 假如有x条边有贡献 ...

  3. [BZOJ3514]CodeChef MARCH14 GERALD07加强版(LCT+主席树)

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2177  Solved: 834 ...

  4. BZOJ 3514: Codechef MARCH14 GERALD07加强版 (LCT维护最大生成树+主席树)

    题意 给出nnn个点,mmm条边.多次询问,求编号在[l,r][l,r][l,r]内的边形成的联通块的数量,强制在线. 分析 LCTLCTLCT维护动态最大生成树,先将每条边依次加进去,若形成环就断掉 ...

  5. 【BZOJ3514】Codechef MARCH14 GERALD07加强版 LCT+主席树

    题解: 还是比较简单的 首先我们的思路是 确定起点 然后之后贪心的选择边(也就是越靠前越希望选) 我们发现我们只需要将起点从后向前枚举 然后用lct维护连通性 因为强制在线,所以用主席树记录状态就可以 ...

  6. BZOJ 3514 Codechef MARCH14 GERALD07加强版 Link-Cut-Tree+划分树

    题目大意: 给定n个点m条边的无向图.求问当图中仅仅有[编号在[l,r]区间内]的边存在时图中的联通块个数 强制在线 注意联通块是指联通了就是同一块,不是Tarjan求的那种块 看到这题的那一刻我就想 ...

  7. 【BZOJ-3514】Codechef MARCH14 GERALD07加强版 LinkCutTree + 主席树

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1288  Solved: 490 ...

  8. [BZOJ 3514]Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES)

    [BZOJ3514] Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES) 题意 \(N\) 个点 \(M\) 条边的无向图,\(K\) 次询问保 ...

  9. 【刷题】BZOJ 3514 Codechef MARCH14 GERALD07加强版

    Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密. 接下来 ...

随机推荐

  1. PlainElastic.Net

    PlainElastic.Net PlainElastic.Net The really plain Elastic Search .Net client. Idea Installation How ...

  2. MySQL索引的设计、使用和优化

    原文:http://bbs.landingbj.com/t-0-243071-1.html MySQL索引概述 所有MySQL列类型可以被索引.对相关列使用索引是提高SELECT操作性能的最佳途径.根 ...

  3. css中如何做到容器按比例缩放

    需求: 一般在响应式中,我们会要求视频的宽高比为16:9或4:3,这么一来就比较头大了.当用户改变浏览器宽度的时候(改变高度不考虑),视频的宽度变了,那么高度也得根据我们要求的16:9或4:3改变. ...

  4. 网络编程--使用TCP协议发送接收数据

    package com.zhangxueliang.tcp; import java.io.IOException; import java.io.OutputStream; import java. ...

  5. vue图表

    https://www.cnblogs.com/powertoolsteam/p/top-9-javascript-charting-libraries.html

  6. C# Note4:XML序列化和反序列化(含加密解密等)

    前言 在项目中,我们经常用到各种配置文件,比如xml文件.binary文件等等,这里主要根据实践经验介绍下xml文件的序列化和反序列化(毕竟最常用). 实践背景:我要做一个用户管理功能,用户账号信息存 ...

  7. Python 命令行工具 argparse 模块使用详解

    先来介绍一把最基本的用法 import argparse parser = argparse.ArgumentParser() parser.parse_args() 在执行 parse_args() ...

  8. ssh 登陆服务器原理

    这里分两种情况,这两种情况都涉及到公钥加密的概念. 由于公钥加密概念作为基础就不在本文进行讨论了. 使用ssh对远程服务器进行密码登录发生了什么: 客户端通过ssh连接服务器 1. 首先服务器把自己的 ...

  9. 日志与python日志组件logging

    1. 日志的相关概念: (1)日志的作用: a. 开发人员进行程序调试 b. 开发人员定位程序故障的位置 c. 运维人员观察应用运行是否正常 (2)日志的等级 a. DEBUG 最详细的日志,用于问题 ...

  10. centOS 开机自启动自己的脚本

    centOS 开机自启动自己的脚本 1. 自己脚本 myservice 如下: #!/bin/bash # chkconfig: # description: myservice .... echo ...