题目:

BZOJ3514

分析:

看到这题真的是一脸懵逼无从下手,只好膜题解。看到「森林的联通块数 = 点数 - 边数」这一句话就立刻什么都会了 QAQ 。

这题最重要的就是意识到上面那个式子(正确性显然)。那么这个问题就变成了:\([l,r]\) 中最多选出多少条边,使得图中不存在环。根据 Kruskal 的原理,贪心地选就能保证选出的边最多,所以我们不妨假定尽量选编号较大的边。

给每条边 \(i\) 设 \(nxt_i\) ,表示从 \(i\) 开始向后依次插入边,插入到 \(nxt_i\) 这条边时会出现 包含 \(i\) 的 环(不存在则为无穷大)。即,如果 \(i\) 和 \(nxt_i\) 同时可选,由于尽量选择标号大的边,所以选上 \(nxt_i\) 而把 \(i\) 删掉。\(nxt_i\) 也可理解为会「废掉」\(i\) 的第一条边。那么答案就是满足 \(i\in[l,r]\) 且 \(nxt[i]\notin[l,r]\) 的边数。这是一个二维数点问题,直接用主席树解决即可。

如何 \(O(n)\) 求出 \(nxt_i\) 呢?考虑从小到大加边,当加入边 \(i\) 时,如果出现了环,那么断掉环上最小的边 \(j\) ,则 \(nxt_j=i\) 。这个过程用 LCT 维护。

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std; namespace zyt
{
template<typename T>
inline bool read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != EOF && c != '-' && !isdigit(c));
if (c == EOF)
return false;
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
return true;
}
template<typename T>
inline void write(T x)
{
static char buf[20];
char *pos = buf;
if (x < 0)
putchar('-'), x = -x;
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
const int N = 2e5 + 10, M = 2e5 + 10, B = 20, P = N + M, INF = 0x3f3f3f3f;
class Link_Cut_Tree
{
private:
struct nulltag {};
struct node
{
int val, min;
bool revtag;
node *fa, *s[2];
node(nulltag)
: val(INF), min(INF), revtag(false)
{
fa = s[0] = s[1] = this;
}
node(const int _val)
: val(_val), min(_val), revtag(false)
{
fa = s[0] = s[1] = null;
}
}*pos[P];
static node *null;
static void update(node *const rot)
{
rot->min = min(rot->val, min(rot->s[0]->min, rot->s[1]->min));
}
static void rev(node *const rot)
{
swap(rot->s[0], rot->s[1]), rot->revtag ^= 1;
}
static void pushdown(node *const rot)
{
if (rot->revtag)
{
if (rot->s[0] != null)
rev(rot->s[0]);
if (rot->s[1] != null)
rev(rot->s[1]);
rot->revtag = 0;
}
}
static void pushdown_all(node *const rot)
{
if (!isrot(rot))
pushdown_all(rot->fa);
pushdown(rot);
}
static bool isrot(const node *const rot)
{
return rot != rot->fa->s[0] && rot != rot->fa->s[1];
}
static bool dir(const node *const rot)
{
return rot == rot->fa->s[1];
}
static void rotate(node *const rot)
{
node *f = rot->fa, *ff = f->fa;
bool d = dir(rot);
if (!isrot(f))
ff->s[dir(f)] = rot;
rot->fa = ff;
f->s[d] = rot->s[!d];
if (rot->s[!d] != null)
rot->s[!d]->fa = f;
rot->s[!d] = f;
f->fa = rot;
update(f);
}
static void splay(node *const rot)
{
pushdown_all(rot);
while (!isrot(rot))
{
node *f = rot->fa;
if (isrot(f))
rotate(rot);
else if (dir(f) ^ dir(rot))
rotate(rot), rotate(rot);
else
rotate(f), rotate(rot);
}
update(rot);
}
static void access(node *rot)
{
for (node *last = null; rot != null; last = rot, rot = rot->fa)
splay(rot), rot->s[1] = last, update(rot);
}
static void mkrot(node *const rot)
{
access(rot), splay(rot), rev(rot);
}
static node *findrot(node *rot)
{
access(rot), splay(rot);
while (rot->s[0] != null)
rot = rot->s[0];
return rot;
}
public:
bool connect(const int x, const int y)
{
return findrot(pos[x]) == findrot(pos[y]);
}
void link(const int x, const int y)
{
node *rot1 = pos[x], *rot2 = pos[y];
mkrot(rot1), splay(rot1), rot1->fa = rot2;
}
void cut(const int x, const int y)
{
node *rot1 = pos[x], *rot2 = pos[y];
mkrot(rot1), access(rot2), splay(rot1);
rot1->s[1] = rot2->fa = null;
update(rot1);
}
int query(const int x, const int y)
{
node *rot1 = pos[x], *rot2 = pos[y];
mkrot(rot1), access(rot2), splay(rot1);
return rot1->min;
}
void init(const int n, const int *const w)
{
for (int i = 1; i <= n; i++)
pos[i] = new node(w[i]);
} }lct;
typedef Link_Cut_Tree LCT;
LCT::node *LCT::null = new LCT::node(LCT::nulltag());
namespace Chairman_Tree
{
struct node
{
int sum, lt, rt;
}tree[M * B];
int cnt;
void add(int &rot, const int pre, const int lt, const int rt, const int pos, const int x)
{
rot = ++cnt;
tree[rot] = tree[pre];
tree[rot].sum += x;
if (lt == rt)
return;
int mid = (lt + rt) >> 1;
if (pos <= mid)
add(tree[rot].lt, tree[pre].lt, lt, mid, pos, x);
else
add(tree[rot].rt, tree[pre].rt, mid + 1, rt, pos, x);
}
int query(const int rot1, const int rot2, const int lt, const int rt, const int ls, const int rs)
{
if (!rot2 || (ls <= lt && rt <= rs))
return tree[rot2].sum - tree[rot1].sum;
int mid = (lt + rt) >> 1;
if (rs <= mid)
return query(tree[rot1].lt, tree[rot2].lt, lt, mid, ls, rs);
else if (ls > mid)
return query(tree[rot1].rt, tree[rot2].rt, mid + 1, rt, ls, rs);
else
return query(tree[rot1].lt, tree[rot2].lt, lt, mid, ls, rs)
+ query(tree[rot1].rt, tree[rot2].rt, mid + 1, rt, ls, rs);
}
}
typedef pair<int, int> pii;
int head[M], w[P], n, m, nxt[M];
pii arr[M];
int work()
{
using namespace Chairman_Tree;
int lastans = 0, q, type;
read(n), read(m), read(q), read(type);
for (int i = 1; i <= n; i++)
w[i] = INF;
for (int i = 1; i <= m; i++)
w[i + n] = i, nxt[i] = m + 1;
lct.init(n + m, w);
for (int i = 1; i <= m; i++)
{
int a, b;
read(a), read(b);
arr[i] = pii(a, b);
if (a == b)
{
nxt[i] = i;
continue;
}
if (lct.connect(a, b))
{
int tmp = lct.query(a, b);
nxt[tmp] = i;
lct.cut(tmp + n, arr[tmp].first);
lct.cut(tmp + n, arr[tmp].second);
}
lct.link(a, i + n), lct.link(i + n, b);
}
for (int i = 1; i <= m; i++)
add(head[i], head[i - 1], 1, m + 1, nxt[i], 1);
while (q--)
{
int l, r;
read(l), read(r);
if (type)
l ^= lastans, r ^= lastans;
write(lastans = (n - query(head[l - 1], head[r], 1, m + 1, r + 1, m + 1)));
putchar('\n');
}
return 0;
}
}
int main()
{
return zyt::work();
}

【BZOJ3514】Codechef MARCH14 GERALD07加强版(LCT_主席树)的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. BZOJ_3514_Codechef MARCH14 GERALD07加强版_主席树+LCT

    BZOJ_3514_Codechef MARCH14 GERALD07加强版_主席树+LCT Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. I ...

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

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

  8. bzoj3514 Codechef MARCH14 GERALD07加强版 lct预处理+主席树

    Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1951  Solved: 746[Submi ...

  9. BZOJ3514: Codechef MARCH14 GERALD07加强版【LCT】【主席树】【思维】

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

  10. BZOJ3514: Codechef MARCH14 GERALD07加强版(LCT,主席树)

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

随机推荐

  1. linux下启动mysql服务(类似于windows下net start mysql)

    1.linux系统启动方式:service mysql start.其类似于windows下net start mysql

  2. Docker+Drone做Java/Tomcat的CI服务

    1. 安装Docker(略过) 2. 编写docker-compose.yaml version: '2' services: drone-server: image: drone/drone:0.8 ...

  3. Scala入门到精通——第二十四节 高级类型 (三)

    作者:摆摆少年梦 视频地址:http://blog.csdn.net/wsscy2004/article/details/38440247 本节主要内容 Type Specialization Man ...

  4. HDU 5301 Buildings(2015多校第二场)

    Buildings Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Tota ...

  5. 微信小程序之 页面跳转 及 调用本地json的假数据调试

    一.微信小程序 跳转页面 小程序页面有2种跳转,可以在wxml页面或者js中: (1)在wxml页面中: <navigator url="../index/index"> ...

  6. 【转载】C# 装箱和拆箱[整理]

    1.      装箱和拆箱是一个抽象的概念 2.      装箱是将值类型转换为引用类型 :拆箱是将引用类型转换为值类型       利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的 ...

  7. 单片机远程控制步进电机、LED灯和蜂鸣器

    通过採用C#语言实现的上位机控制单片机的步进电机模块.LED灯和蜂鸣器模块,使步进电机进行正.反转和停止并控制转速:LED灯模块进行有选择的呼吸式表达:蜂鸣器模块的開始和终止. 上位机通过串口和自己定 ...

  8. android 自己主动拒接后再取消自己主动拒接,该联系人来电界面无图标显示,且点击挂断无反应

    1.    设置一个联系人为自己主动拒接 2.    该联系人来电 3.    取消该联系人的自己主动拒接 4.    该联系人来电 Error: 来电界面无头像显示,直接显示黑屏,且点击拒接butt ...

  9. 大数据处理之道 (htmlparser获取数据&lt;一&gt;)

    一:简单介绍 (1)HTML Parser是一个用于解析Html的Java的库.可採用线性或嵌套两种方式.主要用于网页的转换或提取,他有一些特性:过滤器filter,遍历器visitors,通常的标签 ...

  10. 【bzoj1015】【JSOI2008】【星球大战】【并查集+离线】

    Description 非常久曾经.在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器.并攻下了星系中差点儿全部的星球.这些星球 ...