题目

CF576E

分析:

从前天早上肝到明天早上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;doc = getchar();while (c != '-' && !isdigit(c));if (c == '-')f = true, c = getchar();dox = 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");elsewrite("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();
}

转载于:https://www.cnblogs.com/zyt1253679098/p/10110917.html

【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)相关推荐

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

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

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

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

  3. 暑期集训5:并查集 线段树 练习题G: HDU - 1754

    2018学校暑期集训第五天--并查集 线段树 练习题G  --   HDU - 1754 I Hate It 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.  这让 ...

  4. 暑期集训5:并查集 线段树 练习题F:  HDU - 1166 ​​​​​​​

    2018学校暑期集训第五天--并查集 线段树 练习题F  --   HDU - 1166 敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A ...

  5. 暑期集训5:并查集 线段树 练习题B: HDU - 1213 ​​​​​​​

    2018学校暑期集训第五天--并查集 线段树 练习题B  --   HDU - 1213 How Many Tables Today is Ignatius' birthday. He invites ...

  6. 暑期集训5:并查集 线段树 练习题A:  HDU - 1232 ​​​​​​​

    2018学校暑期集训第五天--并查集 线段树 练习题A  --   HDU - 1232 畅通工程 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅 ...

  7. UVA1455 - Kingdom(并查集 + 线段树)

    UVA1455 - Kingdom(并查集 + 线段树) 题目链接 题目大意:一个平面内,给你n个整数点,两种类型的操作:road x y 把city x 和city y连接起来,line fnum ...

  8. BZOJ 3910 并查集+线段树合并

    思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...

  9. poj 2985(并查集+线段树求K大数)

    解题思路:这道题并查集很容易,合并时找到父节点就直接加上去就ok了.关键是如何求K大数,我一直在想用线段树怎么写,一开始想如果直接记录数的大小那肯定是没戏了,借鉴了一下别人的思路:区间[a,b]记录的 ...

最新文章

  1. git钩子放服务器_服务器git钩子
  2. redux源码分析之一:createStore.js
  3. python装饰器的案例_Python之装饰器的实例
  4. java的注释规范_Java 注释规范
  5. BZOJ 4259 FFT
  6. 【阿里妈妈数据科学系列】第三篇:离线抽样框架下的AB Test
  7. 前端学习(563):干掉block重叠margin重叠
  8. fifo java_java – 如何保证ThreadPoolExecutor中的FIFO执行顺序
  9. Leetcode分类
  10. OSI、TCP/IP or Five-layer(Protocols Use) Model
  11. 数据结构——归并排序
  12. k8s高可用集群_搭建高可用集群(实现方式介绍)---K8S_Google工作笔记0054
  13. 自从微信更新后,广东人都玩疯了!以后语音可以识别英语、粤语啦!
  14. java负零_java数据结构从零基础到负基础
  15. protues7 使用笔记
  16. solidwork 侵权 证据_企业常见版权侵权问题咨询总结
  17. RTX 3090 Ti和RX 6950 XT参数对比
  18. Mobileye REM地图如何解决高精地图落地难点
  19. 985在读硕士晓文大数据学习之路1:出发
  20. cs231n Assignment1--机器学习基本方法与深度学习尝试

热门文章

  1. es6遍历树结构并判断_实现树形结构数据 es6
  2. Vue快速上手笔记2 - 开发环境的搭建
  3. scrapy 中爬取时被重定向_Scrapy详解之scrapy shell
  4. php表单验证代码实例,PHP表单验证实例代码-三体教程在线编辑器
  5. 笔记︱集成学习Ensemble Learning与树模型、Bagging 和 Boosting、模型融合
  6. ASP.NET基础培训 - Cookie的正确利用
  7. 这么说吧,NIO很简单,其实就是个牛逼IO
  8. HBase的JavaAPI使用
  9. django中搜索表单
  10. 大数据分析-时间序列(pandas库 )