2019牛客多校第三场A Graph Games 分块思想
题意:给你一张无向图,设s(x)为与x直接相连的点的集合,题目中有两种操作:
1:1 l r 将读入的边的序列中第l个到第r个翻转状态(有这条边 -> 没这条边, 没这条边 -> 有这条边)
2:2 x y 询问s(x)和s(y)是否相等。
思路(官方题解):首要问题是怎么快速判断s(x)和s(y)是否相等。我们发现边的翻转操作实际上是异或操作,所以不妨给每个点随机一个值,用与x直接相连的点的异或和作为s(x),这样可以快速判断s(x)和s(y)是否相等。判相等解决了,怎么快速维护操作1呢?我们发现好像不好直接维护,因为把一个区间的边翻转了,好像除了遍历,很难知道具体影响了哪些点,或者我们只标记翻转,计算s(x)的时候枚举和x相连的边,判断是否翻转。这两种好像复杂度都比较高,但是我们可以折中一下,我们对点进行分类,根据度数是否大于sqrt(m),分为小点和大点两类。这个套路之前见过,放上链接https://www.cnblogs.com/pkgunboat/p/10995209.html对于小点,边数不超过sqrt(m),直接暴力判断是否翻转就可以了。对于大点,由于大点只有O(sqrt(m))种,相对比较好维护。我们可以对边序列分块,维护每一个块如果整体翻转了对某个大点的贡献。这样,我们在进行区间操作的时候,在块间打翻转标记,在两侧暴力翻转,如果翻转的边的端点是大点,就直接把影响加上。询问的时候,看一下所有块的整体翻转情况,如果整体是翻转的,因为之前已经预处理了所有块对大点的翻转影响,所以把影响加上。这样每次询问复杂度O(sqrt(m))。
代码:
#include <bits/stdc++.h>
#define LL long long
#define pii pair<int, int>
using namespace std;
const int maxn = 200010;
LL val[maxn], now[maxn];
LL f[510][1010];
bool flip[510], v[maxn];
bool is_big[maxn];
vector<pii> G[maxn];
int pos[maxn], L[maxn], R[maxn], mp[maxn], tot;
random_device rd;
mt19937 Random(rd());
//LL Random() {
// return (LL)rand() * rand();
//}
struct edge{
int u, v;
};
edge e[maxn];
LL get(LL mod) {
return ((__int128)Random() * Random()) % mod;
}
void change(int l, int r) {
int p = pos[l], q = pos[r];
if(p == q) {
for (int i = l; i <= r; i++) {
v[i] ^= 1;
if(is_big[e[i].u]) now[e[i].u] ^= val[e[i].v];
if(is_big[e[i].v]) now[e[i].v] ^= val[e[i].u];
}
} else {
for (int i = p + 1; i <= q - 1; i++) {
flip[i] ^= 1;
}
for (int i = L[q]; i <= r; i++) {
v[i] ^= 1;
if(is_big[e[i].u]) now[e[i].u] ^= val[e[i].v];
if(is_big[e[i].v]) now[e[i].v] ^= val[e[i].u];
}
for (int i = l; i <= R[p]; i++) {
v[i] ^= 1;
if(is_big[e[i].u]) now[e[i].u] ^= val[e[i].v];
if(is_big[e[i].v]) now[e[i].v] ^= val[e[i].u];
}
}
}
int main() {
int T, op, x, y, n, m, T1;
srand(time(0));
scanf("%d", &T);
while(T--) {
tot = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
val[i] = get(1e18);
G[i].clear();
now[i] = 0;
flip[i] = 0;
}
for (int i = 1; i <= m; i++) {
scanf("%d%d", &e[i].u, &e[i].v);
G[e[i].u].push_back(make_pair(e[i].v, i));
G[e[i].v].push_back(make_pair(e[i].u, i));
now[e[i].v] ^= val[e[i].u];
now[e[i].u] ^= val[e[i].v];
}
int t = sqrt(m);
int block = t;
for (int i = 1; i <= t; i++) {
L[i] = (i - 1) * block + 1;
R[i] = i * block;
}
if(R[t] < m) {
t++;
L[t] = R[t - 1] + 1;
R[t] = m;
}
for (int i = 1; i <= n; i++) {
if(G[i].size() >= block) {
is_big[i] = 1;
mp[i] = ++tot;
} else {
is_big[i] = 0;
mp[i] = 0;
}
}
assert(tot <= 1000);
assert(t <= 500);
for (int i = 1; i <= t; i++) {
for (int j = 1; j <= tot; j++)
f[i][j] = 0;
for (int j = L[i]; j <= R[i]; j++) {
pos[j] = i;
v[j] = 0;
}
}
for (int i = 1; i <= t; i++) {
for (int j = L[i]; j <= R[i]; j++) {
if(is_big[e[j].u]) {
f[i][mp[e[j].u]] ^= val[e[j].v];
}
if(is_big[e[j].v]) {
f[i][mp[e[j].v]] ^= val[e[j].u];
}
}
}
scanf("%d", &T1);
while(T1--) {
scanf("%d%d%d", &op, &x, &y);
if(op == 1) {
change(x, y);
} else {
LL ans1 = now[x], ans2 = now[y];
if(is_big[x]) {
for (int i = 1; i <= t; i++) {
if(flip[i]) ans1 ^= f[i][mp[x]];
}
} else {
for (int i = 0; i < G[x].size(); i++) {
pii tmp = G[x][i];
if(v[tmp.second] ^ flip[pos[tmp.second]])
ans1 ^= val[tmp.first];
}
}
if(is_big[y]) {
for (int i = 1; i <= t; i++) {
if(flip[i]) ans2 ^= f[i][mp[y]];
}
} else {
for (int i = 0; i < G[y].size(); i++) {
pii tmp = G[y][i];
if(v[tmp.second] ^ flip[pos[tmp.second]])
ans2 ^= val[tmp.first];
}
}
if(ans1 == ans2) {
printf("1");
} else {
printf("0");
}
}
}
printf("\n");
}
}
2019牛客多校第三场A Graph Games 分块思想的更多相关文章
- 2019牛客多校第三场 F.Planting Trees
题目链接 题目链接 题解 题面上面很明显的提示了需要严格\(O(n^3)\)的算法. 先考虑一个过不了的做法,枚举右下角的\((x,y)\),然后二分矩形面积,枚举其中一边,则复杂度是\(O(n^3 ...
- 2019牛客多校第三场D BigInteger——基础数论
题意: 用 $A(n)$ 表示第 $n$ 个只由1组成分整数,现给定一个素数 $p$,求满足 $1 \leq i\leq n, 1 \leq j \leq m, A(i^j) \equiv 0(mo ...
- [2019牛客多校第三场][G. Removing Stones]
题目链接:https://ac.nowcoder.com/acm/contest/883/G 题目大意:有\(n\)堆石头,每堆有\(a_i\)个,每次可以选其中两堆非零的石堆,各取走一个石子,当所有 ...
- [题解]Magic Line-计算几何(2019牛客多校第三场H题)
题目链接:https://ac.nowcoder.com/acm/contest/883/H 题意: 给你偶数个点的坐标,找出一条直线将这n个点分成数量相等的两部分 并在这条直线上取不同的两个点,表示 ...
- [题解]Crazy Binary String-前缀和(2019牛客多校第三场B题)
题目链接:https://ac.nowcoder.com/acm/contest/883/B 题意: 给你一段长度为n,且只有 ‘0’ 和 ‘1’ 组成的字符串 a[0,...,n-1].求子串中 ‘ ...
- 启发式分治:2019牛客多校第三场 G题 Removing Stones
问题可以转换为求有多少个区间数字的总和除2向下取整大于等于最大值.或者解释为有多少个区间数字的总和大于等于最大值的两倍(但是若区间数字总和为奇数,需要算作减1) 启发式分治: 首先按最大值位置分治,遍 ...
- 2019牛客多校第三场B-Crazy Binary String(前缀和+思维)
Crazy Binary String 题目传送门 解题思路 把1记为1,把0记为-1,然后求前缀和,前缀和相等的就说明中间的01数一样.只要记录前缀和数值出现的位置即可更新出答案. 代码如下 #in ...
- 2019牛客多校第三场H-Magic Line
Magic Line 题目传送门 解题思路 因为坐标的范围只有正负1000,且所有点坐标都是整数,所以所有点相连构成的最大斜率只有2000,而我们能够输出的的坐标范围是正负10^9.所以我们先把这n个 ...
- 2019牛客多校第三场J-LRU management(map+双向链表)
LRU management 题目传送门 解题思路 用map索引对应地址,用双向链表维护序列. 代码如下 #include <bits/stdc++.h> #define INF 0x3f ...
随机推荐
- Sass值列表
所谓值列表 (lists) 是指 Sass 如何处理 CSS 中: margin: 10px 15px 0 0 或者: font-face: Helvetica, Arial, sans-serif ...
- css解决表格嵌套表格出现多余边框的方法
这是昨天遇到的问题因为表格里面套了层表格出现了双层的边框,昨天折腾了很久最终才知道有个属性叫 border-style:hidden 可以解决边框冲突! 左边的边框加上了该属性之后
- 嵌入式系统的性能测试(1) – lmbench篇
要评价一个系统的性能,通常有不同的指标,相应的会有不同的测试方法和测试工具.既有比较成熟的商业测试软件,也有许多优秀的开源工具来完成这个任务.本文简要介绍如何使用lmbench来完成系统综合性能测试. ...
- 【串线篇】Mybatis缓存之一级缓存
1.体会 一级缓存:MyBatis:SqlSesion级别的缓存:默认存在,不需要设置. 机制:只要之前查询过的数据,mybatis就会保存在一个缓存中(Map):下次获取直接从缓存中拿:当前sess ...
- NET Core+win10+Jenkins+Github持续集成
本篇和上一篇NET Core+win10+Jenkins+Gogs+open ssh持续集成没什么区别,只不过源码库换成github. 这里有两点不一样的是: 获取的代码的凭证不用用户名和密码用sec ...
- Oracle12c RAC数据导出至Oracle11g
一.Oracle12c导出数据 1.连接数据库 sqlplus / as sysdba 2.查看pdbs show pdbs; 3.切换pdb alter session set container= ...
- shell脚本学习(7)sort
1 sort的格式 sort [options] [files] sort 参数 文件 2 参数 -t 用单个符char作为默认的字段分隔符, 默认字段分隔符是空白 参数-k 用来定义排序键值字段 ...
- spfa模板(洛谷3371)
洛谷P3371 //spfa:求s到各点的最短路,可含负权边 #include <cstdio> using namespace std; ,max_m=,inf=; struct ety ...
- iOS设计模式之装饰者模式
一,什么是装饰模式 模式定义 装饰者包含被装饰者的所有接口和引用,方法实现完全是引用调用自己的方法,在装饰者子类添加新功能. 注释: Category不要重写被装饰对象的方法,否则改变了被装饰对象的行 ...
- linux0.11源码内核——系统调用,int80的实现细节
linux0.11添加系统调用的步骤 假设添加一个系统调用foo() 1.修改include/linux/sys.h 添加声明 extern int foo(); 同时在sys_call_table数 ...