题目链接


题目大意:

你有个点集合SSS,每次往集合里面加点或者删点(如果要加的点出现过),如果(x1,y1),(x2,y1),(x1,y2),(x2,y2)(x1,y1),(x2,y1),(x1,y2),(x2,y2)(x1,y1),(x2,y1),(x1,y2),(x2,y2)只要出现其中3个第4个就会出现?
问你最终这个点集会变成多少个点在里面


解题思路:

很明显的一点4个点连线会构成一个环,我们对这个点我们可以直接用并查集去维护行和列拆开
例如(x1,y1)(x1,y1)(x1,y1)我们直接把x1←→(y1+n)x1\leftarrow\rightarrow (y1+n)x1←→(y1+n)两个集合合并,当x2←→y1+n,x1←→y2+nx2\leftarrow\rightarrow y1+n,x1\leftarrow\rightarrow y2+nx2←→y1+n,x1←→y2+n
的时候x2←→y2+nx2\leftarrow\rightarrow y2+nx2←→y2+n是不是也成立了!!!

现在就是怎么求最终有多少个点在里面?
我们不考虑删除操作只考虑加点该怎么办?
我们在合并两个集合的时候我们发现新增的点数本质上就是两个集合里面的(x,y) 互相配对,参生的结果那么,我们只有维护每个块里面多少个x点,多少个y点就可以了!!

对于删除操作,我们可以直接用线段树分治去搞,用可撤销并查集维护结果就可以了


#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 700010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}
map<PII,int> tim;
int q;
struct dsu {int fa[maxn];vector<PII> loop; int siz[maxn];// 维护块的大小int sizn[maxn];// 维护y的个数inline void init(int n) {loop.clear();for(int i = 1; i <= n; ++ i) fa[i] = i, siz[i] = 1;for(int i = n+1; i <= 2 * n; ++ i) fa[i] = i, siz[i] = 1, sizn[i] = 1;// 初始化y} inline int find(int u) { // 可撤销并查集是按秩合并。while(u != fa[u]) u = fa[u];return u;}
}dsu;
ll ans = 0;
struct Segtree {vector<PII> tr[maxn<<2];inline void add(int rt, int l, int r, int posl, int posr, PII val) {if(l >= posl && r <= posr) {tr[rt].push_back(val);return;}if(posl <= mid) add(Lson,posl,posr,val);if(posr > mid) add(Rson,posl,posr,val);}inline void dfs(int rt, int l, int r) {int las = dsu.loop.size();ll backup = ans;for(auto it : tr[rt]) {int fx = dsu.find(it.first);int fy = dsu.find(it.second+300000);if(fx == fy) continue;if(dsu.siz[fx] > dsu.siz[fy]) swap(fx,fy);ans += 1ll * dsu.sizn[fx] * (dsu.siz[fy] - dsu.sizn[fy]);ans += 1ll * dsu.sizn[fy] * (dsu.siz[fx] - dsu.sizn[fx]);dsu.fa[fx] = fy;dsu.siz[fy] += dsu.siz[fx];dsu.sizn[fy] += dsu.sizn[fx];dsu.loop.push_back({fx,fy});}if(l == r) {cout << ans << " ";} else {dfs(Lson);dfs(Rson);}ans = backup;while(las < dsu.loop.size()) {auto bac = dsu.loop.back();dsu.loop.pop_back();dsu.fa[bac.first] = bac.first;dsu.siz[bac.second] -= dsu.siz[bac.first]; dsu.sizn[bac.second] -= dsu.sizn[bac.first]; }}
}sgt;int main() {IOS;cin >> q;for(int i = 1; i <= q; ++ i) {int u, v;cin >> u >> v;if(!tim.count({u,v})) tim[{u,v}] = i;else {sgt.add(1,1,q,tim[{u,v}],i-1,(PII){u,v});tim.erase({u,v});}}  for(auto it : tim) {sgt.add(1,1,q,it.second,q,it.first);}dsu.init(300000);sgt.dfs(1,1,q);return 0;
}
/*
3
1 1
1 2
2 1
*/

线段树分治 ---- F. Extending Set of Points(线段树分治 + 可撤销并查集)相关推荐

  1. 线段树分治 ---- CF1217F - Forced Online Queries Problem(假离线 可撤销并查集 + 线段树分治)详解

    题目链接 题目大意 解题思路: 我一开始想到可以用可撤销并查集去维护这种删边加边的操作,但是有个缺点是每次撤销都有把后面的边全部撤销复度是O(n2)O(n^2)O(n2) 首先我们考虑这种动态加边删边 ...

  2. 【BZOJ4025】二分图(可撤销并查集+线段树分治)

    题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ...

  3. 【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)

    题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...

  4. CF603E-Pastoral Oddities【CDQ分治,可撤销并查集】

    正题 题目链接:https://www.luogu.com.cn/problem/CF603E 题目大意 开始时有nnn个点,没有边. 依次加入mmm条带权的边,每次加入后询问是否存在一个边集,满足每 ...

  5. [WC2005]双面棋盘,洛谷P4121,线段树分治+可撤销并查集

    正题 这题主要是来练手的,因为没写过可撤销的并查集,大概就是把每一个格子看成一个点,然后格子直接的边有很多的出现区间,把这些出现区间和对应的颜色打到线段树上,然后用可撤销的并查集来维护就可以了. #i ...

  6. bzoj 4025: 二分图(可撤销并查集+CDQ分治)

    4025: 二分图 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 1726  Solved: 641 [Submit][Status][Discus ...

  7. P5787 二分图 /【模板】线段树分治(线段树分治、并查集)

    关于什么是合理的实现 解析 本题把并查集写在了题面上 然而,我却一直沉浸在一个及其通用的判断二分图的方法中: 一个图是二分图的充要条件是它没有奇环 怎么维护这个玩意?带权并查集! 怎么套线段树分治?可 ...

  8. 分门别类刷leetcode——高级数据结构(字典树,前缀树,trie树,并查集,线段树)

    目录 Trie树(字典树.前缀树)的基础知识 字典树的节点表示 字典树构造的例子 字典树的前序遍历 获取字典树中全部单词 字典树的整体功能 字典树的插入操作 字典树的搜索操作 字典树的前缀查询 字典树 ...

  9. CodeForces - 1217F Forced Online Queries Problem(线段树分治+并查集撤销)

    题目链接:点击查看 题目大意:给出 nnn 个点,初始时互相不存在连边,需要执行 mmm 次操作,每次操作分为两种类型: 1xy1 \ x \ y1 x y:如果 (x,y)(x,y)(x,y) 之间 ...

最新文章

  1. JVM调优:运行参数,内存模型,mat、jps、jstat、jmap、jstack、jvisualvm工具的使用
  2. 如何降低微服务测试成本?
  3. 细说Nginx配置文件
  4. C# 去除文件或 文件夹只读属性
  5. mysql 列级权限授予用户_mysql 用户及权限管理 小结
  6. C语言i++和++i的区别和用法
  7. 学会这2招,不用设计师,一样能做出精美炫酷的可视化大屏模板
  8. vscode 智能提示失效
  9. C# WinForm TextBox 文本垂直居中实现
  10. 如何创建和共享iGoogle标签
  11. kafka seek方法
  12. 环境配置 python 3.6+Anaconda+cuda9.0+cudNN7.0+Tensorflow
  13. Lua 程序设计——Lua 教程01
  14. 【linux 学习】在Linux中经常用到的cmake、make、make install等命令解析
  15. 如何在安卓手机上编辑Excel表格?
  16. 最容易理解的SVM算法原理
  17. 腾讯云TSF微服务平台及ServiceMesh技术实践
  18. Redis实战demo
  19. datawhale深入浅出Pytorch02——Pytorch各个模块组件
  20. K8S(Rancher)Ingress 规则 - Nginx 反向代理重定向

热门文章

  1. ACMNO.21 C语言-逆序输出 输入10个数字,然后逆序输出。 输入 十个整数 输出 逆序输出,空格分开 样例输入 1 2 3 4 5 6 7 8 9 0
  2. 10张 GIF 动图让你弄懂递归等概念
  3. 【OpenCV 4开发详解】轮廓外接多边形
  4. 【OpenCV 4开发详解】图像腐蚀
  5. Python函数及其参数
  6. Java线程池使用与原理
  7. 如何添加ORACLE 的 ODBC
  8. 1. vi 与 vim 有什么区别呢,它们之间有什么关系?
  9. scau 1142 巡逻的士兵(分治)
  10. Unity热门插件推荐