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

news/2024/7/7 19:38:20

题目链接


题目大意

在这里插入图片描述


解题思路:

我一开始想到可以用可撤销并查集去维护这种删边加边的操作,但是有个缺点是每次撤销都有把后面的边全部撤销复度是O(n2)O(n^2)O(n2)

  1. 首先我们考虑这种动态加边删边的问题,如果是离线的话,那就是线段树分治+可撤销的并查集的模板题
  2. 但是这是强制在线,但是这是虚伪的强制在线就是,每次个操作最多有两种的结果。
    lst={0,1}lst=\{0,1\}lst={0,1}, 最多也就2×m2\times m2×m个操作
  3. 就是我们有条有若干段存在的时间,我们插进线段树里面,用线段树去维护撤销顺序
  4. 首先我们先把两种结果都插进线段树里面,注意线段树分治本质是一个半在线算法
  5. 严格来说我们一开始只是把操作给划分成logloglog块,但是没有调用并查集
  6. 最后一次对整个线段树来个整题的遍历,实际上线段树上面的遍历其实也和你在线处理没什么去区别,你用map去维护选择的边,因为你每次都是递归到叶子节点里面那么本质上也就是再在线处理,然后在加边的时候没有被选择过的边就不要加
    写了个假板子调了半天

AC code

#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 = 500010;
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...);
}
int n, m, k;
struct Edge {int op, x, y;
}e[maxn];
unordered_map<int,int> mp[maxn];
struct dsu {int fa[maxn], siz[maxn];struct inf {int fx, fy;};vector<inf> stk;void init(int n) {stk.clear();for(int i = 0; i <= n; ++ i) fa[i] = i, siz[i] = 1;}int find(int x) {return fa[x] == x ? x : find(fa[x]);}void merge(int x, int y) {int fx = find(x);int fy = find(y);if(fx == fy) return;if(siz[fx] > siz[fy]) swap(fx,fy);fa[fx] = fy;siz[fy] += siz[fx];stk.push_back({fx,fy});}
}dsu;int las=0;struct Segtree {vector<PII> q[maxn<<2];void update(int rt, int l, int r, int L, int R, PII idx) {if(L <= l && R >= r) {q[rt].push_back(idx);return;}if(L <= mid) update(Lson,L,R,idx);if(R > mid) update(Rson,L,R,idx);}void dfs(int rt, int l, int r) {int lasttop = dsu.stk.size();for(auto it : q[rt]) {if(!mp[it.first][it.second]) continue;dsu.merge(it.first,it.second);}		if(l == r) { // 叶子节点跟新答案int x = (e[l].x + las - 1) % n + 1;int y = (e[l].y + las - 1) % n + 1;if(x > y) swap(x,y);if(e[l].op == 2) {las = (dsu.find(x) == dsu.find(y));cout << las;} else mp[x][y] ^= 1;} else {dfs(Lson);dfs(Rson);}while((int)dsu.stk.size() > lasttop) { // 插销dsuauto it = dsu.stk.back();dsu.stk.pop_back();dsu.fa[it.fx] = it.fx;dsu.siz[it.fy] -= dsu.siz[it.fx];}}
} sgt;int main() {read(n,m);dsu.init(n);for(int i = 1; i <= m; ++ i) {int op, x, y;read(op, x, y);e[i] = {op,x,y};if(op == 1) {for(int j = 0; j <= 1; ++ j) {int l = (x + j - 1) % n + 1;int r = (y + j - 1) % n + 1;if(l > r) swap(l,r);if(mp[l].count(r) && mp[l][r] <= i) sgt.update(1,1,m+1,mp[l][r],i,{l,r});mp[l][r] = i + 1;}} }for(int i = 1; i <= n; ++ i) {for(auto it : mp[i]) if(it.second != m+1)sgt.update(1,1,m+1,it.second,m+1,{i,it.first});mp[i].clear();}sgt.dfs(1,1,m+1);return 0;
}

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

相关文章

秘籍 | 机器学习数据集网址大全

作者 | Will Badr译者 | Linstancy整理 | Jane出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;要找到一定特定的数据集可以解决各种机器学习问题&#xff0c;是一件很难的事情。越来越多企业或研究机构将自己的数据集公开&#xff0c;已经成为全球的趋势&#xff0c;…

第一个Servlet和Jsp

为什么80%的码农都做不了架构师&#xff1f;>>> 第一个Servlet和Jsp 开发Servlet有3种方法1.Servlet接口2.继承GenericServlet3.继承HttpServlet Tomcat 9部署Servlet 1.Tomcat的安装目录的webapps目录&#xff0c;可以看到ROOT&#xff0c;examples, tomcat-docs之…

Dungeon Master(bfs)广度优先搜索

描述 You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is composed of unit cubes which may or may not be filled with rock. It takes one minute to move one unit north, south, east, west, up or down. You cannot move diagonal…

你的代码将会被GitHub埋在北极,保存1000年!

点击上方“视学算法”&#xff0c;选择加"星标"或“置顶”重磅干货&#xff0c;第一时间送达晓查 发自 凹非寺 本文转载自&#xff1a;量子位&#xff08;QbitAI&#xff09;你写的代码将被会被GitHub保存1000年。GitHub是不是疯了&#xff1f;有网友吐槽&#xff1a…

明晚8点公开课 | 用AI给旧时光上色!详解GAN在黑白照片上色中的应用

在改革开放40周年之际&#xff0c;百度联合新华社推出了一个刷屏级的H5应用——用AI技术为黑白老照片上色&#xff0c;浓浓的怀旧风勾起了心底快被遗忘的时光。想了解如何给老照片上色&#xff1f;本次公开课中&#xff0c;我们邀请到了百度高级研发工程师李超&#xff0c;他的…

开启Mac充电提示音

2019独角兽企业重金招聘Python工程师标准>>> 开启Mac充电提示音&#xff1a; MBP插电的时候&#xff0c;和苹果手机声音效果一样&#xff0c;“叮” 还是“咚”的一声。 解决&#xff1a; 开启&#xff1a; //打开终端&#xff0c;复制粘贴回车defaults write com.a…

Splay ---- 2018牛客多校第三场 区间翻转搞区间位移 或者 rope可持久化块状链表

题目链接 题目大意&#xff1a; 就是每次把牌堆中若干个连续的牌放到堆顶&#xff0c;问你最后牌的序列。 解题思路&#xff1a; Splay 区间翻转的模板题&#xff1a; 对于一个区间[1,2,3,4,5,6,7,8][1,2,3,4,5,6,7,8][1,2,3,4,5,6,7,8] 你要把[3,4,5][3,4,5][3,4,5]拿到前面…

UVA11624 Fire!(bfs)

相信大家已经读过题目了&#xff0c;我就搬一下洛谷的翻译&#xff1a; 题目大意 你的任务是帮助Joe走出一个大火蔓延的迷宫。Joe每分钟可以走到上下左右4个方向的相邻格子之一&#xff0c;而所有着火的格子都会四周蔓延&#xff08;即如果某个空格子与着火格子有公共边&#x…