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

news/2024/7/5 3:21:24

题目链接


题目大意:

你有个点集合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+nx2y1+n,x1y2+n
的时候x2←→y2+nx2\leftarrow\rightarrow y2+nx2y2+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
*/

http://lihuaxi.xjx100.cn/news/286006.html

相关文章

热榜第一!GitHub 标星 5.6w,如何用 Python 实现所有算法?

转自 | 大数据文摘编译 | 周素云、蒋宝尚学会了 Python 基础知识&#xff0c;想进阶一下&#xff0c;那就来点算法吧&#xff01;毕竟编程语言只是工具&#xff0c;结构算法才是灵魂。新手如何入门 Python 算法&#xff1f;几位印度小哥在 GitHub 上建了一个各种 Python 算法的…

图论-有向图的连通性模板题(hdu1296)(hdu1827)

1.强连通分量&#xff1a; 强连通分量可以理解为边数最少的情况下是一个环。 这里写了一个模板题用的是tarjan算法&#xff0c;当然还有其他算法。 tarjan算法的关键其实还是对于num数组和low数组的使用 然后可以用栈来分离不同的ssc 感觉跟双边连通分量有异曲同工之妙 第一题…

10门必看的机器学习免费课程

整理 | 琥珀出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;文本将介绍来自全球10所著名学府的机器学习和数据科学领域的免费公开课程&#xff0c;范围涉及从入门机器学习到自然语言处理等。1、机器学习华盛顿大学链接&#xff1a;https://courses.cs.washington.ed…

用Python实现一个简单的线程池

线程池的概念是什么&#xff1f;在面向对象编程中&#xff0c;创建和销毁对象是很费时间的&#xff0c;因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是 如此&#xff0c;虚拟机将试图跟踪每一个对象&#xff0c;以便能够在对象销毁后进行垃圾回收。所以提高服务…

根号均摊 ---- E. Xenia and Tree(树形dp + 暴力根号均摊)

题目大意 题目大意&#xff1a; 你有一颗树&#xff1a;树开始时候1号点是红色的 现在就是你有两次操作&#xff1a; 1 u 把u点涂成红色 2 u 询问离u点最近红点在哪里&#xff1f; 数据范围是n,m∈[1,1e5]n,m\in[1,1e5]n,m∈[1,1e5]时间限制是5s5s5s如果直接查询我们是可以直接…

转置卷积实现

import tensorflow as tf import numpy as np import tensorflow as keras from tensorflow.keras import layers,optimizers,losses #创建X矩阵&#xff0c;高宽各位5*5 xtf.range(16)1 #调整为合法的维度张量 xtf.reshape(x,[1,4,4,1]) xtf.cast(x,dtypetf.float32) #创建固定…

全家都是博士是一种什么样的体验?

那些在北大未名湖畔或者清华园里&#xff0c;寒窗苦读获得博士学位的学子&#xff0c;都是家长们眼中“别人的孩子”。身边的朋友以及街坊邻居听闻博士的名号&#xff0c;都会投来敬佩而崇拜的目光。虽然如今随着学历水涨船高&#xff0c;博士学位存在一定程度的贬值&#xff0…

来自程序员的福利!用Python做一款翻译软件

来源 | Ahab杂货铺&#xff08;ID&#xff1a;PythonLearningCamp&#xff09;前两天吃了平哥的一波狗粮&#xff0c;他给女朋友写了一个翻译软件&#xff0c;自己真真切切的感受到了程序员的浪漫。在学习requests请求的时候做过类似的Demo&#xff0c;给百度翻译发送一个post请…