【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)
题目
分析:
从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下。
首先做这题之前推荐一道很相似的题:【BZOJ4025】二分图(可撤销并查集+线段树分治)
大力每个颜色维护一个并查集,就很像上面那道题了。但是存在一个问题:在处理线段树区间\([l,r]\)时,可能并不知道\(l\)处的修改是否成功,所以不知道\(l\)处修改的边具体是什么颜色的。
我的解决方案是:处理区间\([l,r]\)时忽略\(l\)处修改的边。先向左子树递归,递归到叶子时判断本次修改颜色能否成功。然后回溯后向右子树递归前将这条边加入。
代码:
solve函数的第四个参数表示现在是否已经忽略了\(l\)处修改的边。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <queue>
#include <bitset>
#include <stack>
using namespace std;
namespace zyt
{
template<typename T>
inline void read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != '-' && !isdigit(c));
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
}
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);
}
inline void write(const char *const s)
{
printf("%s", s);
}
const int N = 5e5 + 10, B = 19, K = 51;
int n, m, k, q, head[1 << (B + 1) | 11], ecnt;
struct UFS
{
int fa[N], rk[N];
bitset<N> dis;
struct node
{
UFS &ufs;
int x, y, fa, rk, dis;
};
static stack<node> sta;
inline void init()
{
for (int i = 0; i < N; i++)
fa[i] = i, rk[i] = 1;
dis = 0U;
}
int f(const int x)
{
return x == fa[x] ? x : f(fa[x]);
}
int dist(const int x)
{
return x == fa[x] ? dis[x] : dist(fa[x]) ^ dis[x];
}
inline bool merge(const int u, const int v)
{
int x = f(u), y = f(v);
if (x == y)
return dist(u) ^ dist(v);
if (rk[x] > rk[y])
swap(x, y);
sta.push((node){*this, x, y, fa[x], rk[y], dis[x]});
fa[x] = y, dis[x] = dis[x] ^ dist(u) ^ dist(v) ^ 1;
if (rk[x] == rk[y])
++rk[y];
return true;
}
static inline int set_undo()
{
return sta.size();
}
static inline void undo(const int bck)
{
while (sta.size() > bck)
{
UFS &now = sta.top().ufs;
now.fa[sta.top().x] = sta.top().fa;
now.rk[sta.top().y] = sta.top().rk;
now.dis[sta.top().x] = sta.top().dis;
sta.pop();
}
}
}ufs[K];
stack<UFS::node> UFS::sta;
struct edge
{
int id, next;
}e[N * B];
inline void add(const int a, const int b)
{
e[ecnt] = (edge){b, head[a]}, head[a] = ecnt++;
}
struct ed
{
int u, v;
}arr[N];
struct node
{
int ed, col;
}mdf[N];
int pre[N], nxt[N], last[N];
namespace Segment_Tree
{
void insert(const int rot, const int lt, const int rt, const int ls, const int rs, const int id)
{
if (ls <= lt && rt <= rs)
{
add(rot, id);
return;
}
int mid = (lt + rt) >> 1;
if (ls <= mid)
insert(rot << 1, lt, mid, ls, rs, id);
if (rs > mid)
insert(rot << 1 | 1, mid + 1, rt, ls, rs, id);
}
void solve(const int rot, const int lt, const int rt, bool flag)
{
int mid = (lt + rt) >> 1;
int bck = UFS::set_undo();
bool f = false;
for (int i = head[rot]; ~i; i = e[i].next)
{
int now = e[i].id;
if (lt == now)
{
flag = true;
continue;
}
UFS &u = ufs[mdf[now].col];
ed &edg = arr[mdf[now].ed];
if (mdf[now].col)
u.merge(edg.u, edg.v);
}
if (lt == rt)
{
if (!ufs[mdf[lt].col].merge(arr[mdf[lt].ed].u, arr[mdf[lt].ed].v))
mdf[lt].col = mdf[pre[lt]].col, write("NO");
else
write("YES");
putchar('\n');
}
else
{
solve(rot << 1, lt, mid, f | flag);
if (f | flag)
ufs[mdf[lt].col].merge(arr[mdf[lt].ed].u, arr[mdf[lt].ed].v);
solve(rot << 1 | 1, mid + 1, rt, false);
}
UFS::undo(bck);
}
}
int work()
{
using namespace Segment_Tree;
memset(head, -1, sizeof(head));
read(n), read(m), read(k), read(q);
for (int i = 1; i <= k; i++)
ufs[i].init();
for (int i = 1; i <= m; i++)
read(arr[i].u), read(arr[i].v);
for (int i = 1; i <= q; i++)
{
read(mdf[i].ed), read(mdf[i].col);
nxt[i] = q + 1;
}
for (int i = 1; i <= q; i++)
{
if (last[mdf[i].ed])
pre[i] = last[mdf[i].ed];
last[mdf[i].ed] = i;
}
for (int i = q; i > 0; i--)
nxt[pre[i]] = i;
for (int i = 1; i <= q; i++)
insert(1, 1, q, i, nxt[i] - 1, i);
solve(1, 1, q, false);
return 0;
}
}
int main()
{
return zyt::work();
}
【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)的更多相关文章
- 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic
本题可化成更一般的问题:离线动态图询问连通性 当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常 ...
- 【BZOJ4025】二分图(可撤销并查集+线段树分治)
题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ...
- [CSP-S模拟测试]:地理课(并查集+线段树分治)
题目传送门(内部题146) 输入格式 从$geography.in$读入数据. 第一行两个数$n,m$,表示有$n$个点,$m$个时刻.接下来$m$行每行三个数,要么是$1\ u\ v$,要么是$2\ ...
- UVA1455 - Kingdom(并查集 + 线段树)
UVA1455 - Kingdom(并查集 + 线段树) 题目链接 题目大意:一个平面内,给你n个整数点,两种类型的操作:road x y 把city x 和city y连接起来,line fnum ...
- 并查集&线段树&树状数组&排序二叉树
超级无敌巨牛逼并查集(带权并查集)https://vjudge.net/problem/UVALive-4487 带删点的加权并查集 https://vjudge.net/problem/UVA-11 ...
- BZOJ 3910 并查集+线段树合并
思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...
- bzoj 3237 连通图 - 并查集 - 线段树
Input Output Sample Input 4 5 1 2 2 3 3 4 4 1 2 4 3 1 5 2 2 3 2 1 2 Sample Output Connected Disconne ...
- 【xsy2506】 bipartite 并查集+线段树
题目大意:有$n$个点,你需要操作$m$次.每次操作为加入/删除一条边. 问你每次操作后,这$n$个点构成的图是否是二分图. 数据范围:$n,m≤10^5$. 此题并没有强制在线,考虑离线做法. 一条 ...
- 并查集 + 线段树 LA 4730 Kingdom
题目传送门 题意:训练指南P248 分析:第一个操作可以用并查集实现,保存某集合的最小高度和最大高度以及城市个数.运用线段树成端更新来统计一个区间高度的个数,此时高度需要离散化.这题两种数据结构一起使 ...
随机推荐
- 谈谈TCP中的TIME_WAIT
所以,本文也来凑个热闹,来谈谈TIME_WAIT. 为什么要有TIME_WAIT? TIME_WAIT是TCP主动关闭连接一方的一个状态,TCP断开连接的时序图如下: 当主动断开连接的一方(Initi ...
- Crackme3 破解教程
Crackme3 破解教程 1.先用PEiD对 Crackme3进行 壳测试 点击File右边的按钮,选中Crackme3 结果如下图所示: 即 无壳. 试运行软件 点击 Register now! ...
- MongoDB 数据文件备份与恢复
备份与恢复数据对于管理任何数据存储系统来说都是非常重要的. 1.冷备份与恢复——创建数据文件的副本(前提是要停止MongoDB服务器),也就是直接copy MongoDB将所有数据都存储在数据目录下, ...
- 有一张表里面有上百万的数据,在做查询的时候,如何优化?从数据库端,java端和查询语句上回答
原文:https://www.2cto.com/database/201612/580140.html 1)数据库设计方面: a. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 o ...
- noip模拟赛 whzzt-Conscience
分析:数据中并不存在无解的情况...... 每个摄像头都要覆盖尽可能多的点,按照y从小到大排序.对于每一列,只用判断第一个没有被观测到的就可以了,这个点必须要放摄像头,因为除了它自己没有其它的摄像头能 ...
- cpus Vs cpu period and cpu quota
1. https://docs.oracle.com/cd/E37670_01/E75728/html/section-zb1_wqw_gt.html To control a container' ...
- 如何修改ICO文件的尺寸
使用Axialis IconWorkshop,该软件下载地址: http://www.xiazaiba.com/html/161.html 尺寸过大的ICO将无法作为应用程序的图标,如下图所示,这些素 ...
- android传感器;摇一摇抽签功能
package com.kane.sensortest; import java.util.Random; import android.hardware.Sensor; import android ...
- JAVA学习(三):Java基础语法(变量、常量、数据类型、运算符与数据类型转换)
Java基础语法(变量.常量.数据类型.运算符与数据类型转换) 1.变量 Java中.用户能够通过指定数据类型和标识符来声明变量.其基本的语法为: DataType identifier; 或 Dat ...
- POJ 题目3667 Hotel(线段树,区间更新查询,求连续区间)
Hotel Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 13805 Accepted: 5996 Descriptio ...