http://www.lydsy.com/JudgeOnline/problem.php?id=3514 (题目链接)

题意

  给出$n$个点$m$条边的无向图,询问保留图中编号在$[l,r]$的边的时候图中的连通块的个数。

Solution

  将边的编号作为权值用LCT维护一个最大生成树,同时记录一下加入当前边$i$会把哪一条原本在生成树中的边踢掉,记作$ntr[i]$。如果不会踢掉任意一条边,那么$ntr[i]=0$。如果$i$是自环,那么$ntr[i]=i$。

  求出$ntr$数组有什么用呢,我们以它构建一棵主席树。对于一个询问$[l,r]$,我们想知道在这些边中有用的边有几条,那么有用的边$ntr$的前一条边的编号一定是在$l$之前的,所以我们在主席树上查询一下区间$[l,r]$中$ntr$在$[0,l-1]$中的边有几条。这样查出来的值就是有用的边的条数,每加入一条有用的边,都会时连通块个数-1,于是我们就可以统计答案了。

细节

  cut的时候cut的是被ntr的边两端的节点,手一快就打错了,还查了好久T_T

代码

// bzoj3514
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define lim 1000000000
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;const int maxn=200010;
int n,m,Q,T,ans,rt[maxn],ntr[maxn];
struct edge {int u,v;}e[maxn];
struct node {int son[2],s,rev;int& operator [] (int x) {return son[x];}
};namespace LCT {int fa[maxn<<1];node tr[maxn<<1];void reverse(int x) {tr[x].rev^=1;swap(tr[x][0],tr[x][1]);}void pushup(int x) {tr[x].s=x<=n ? inf : x;int l=tr[x][0],r=tr[x][1];if (l) tr[x].s=min(tr[x].s,tr[l].s);if (r) tr[x].s=min(tr[x].s,tr[r].s);}void pushdown(int x) {if (tr[fa[x]][0]==x || tr[fa[x]][1]==x) pushdown(fa[x]);if (tr[x].rev) {if (tr[x][0]) reverse(tr[x][0]);if (tr[x][1]) reverse(tr[x][1]);tr[x].rev^=1;}}void rotate(int x) {int y=fa[x],z=fa[y],l,r;l=tr[y][1]==x;r=l^1;if (tr[z][0]==y || tr[z][1]==y) tr[z][tr[z][1]==y]=x;fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;tr[y][l]=tr[x][r];tr[x][r]=y;pushup(y);pushup(x);}void splay(int x) {pushdown(x);while (tr[fa[x]][0]==x || tr[fa[x]][1]==x) {int y=fa[x],z=fa[y];if (tr[z][0]==y || tr[z][1]==y) {if (tr[z][0]==y ^ tr[y][0]==x) rotate(x);else rotate(y);}rotate(x);}}void access(int x) {for (int y=0;x;y=x,x=fa[x])splay(x),tr[x][1]=y,pushup(x);}void makeroot(int x) {access(x);splay(x);reverse(x);}int query(int x,int y) {makeroot(x);access(y);splay(y);return tr[y].s;}void link(int x,int y) {makeroot(x);fa[x]=y;}void cut(int x,int y) {makeroot(x);access(y);splay(y);fa[x]=tr[y][0]=0;pushup(y);}int find(int x) {return fa[x] ? find(fa[x]) : x;}void main() {for (int i=1;i<=m;i++) {scanf("%d%d",&e[i].u,&e[i].v);if (e[i].u==e[i].v) ntr[i]=i;else if (find(e[i].u)==find(e[i].v)) {int x=query(e[i].u,e[i].v);ntr[i]=x-n;cut(x,e[x-n].u);cut(x,e[x-n].v);link(i+n,e[i].u);link(i+n,e[i].v);}else ntr[i]=0,link(i+n,e[i].u),link(i+n,e[i].v);}}
}namespace Chairtree {int sz;node tr[maxn*40];void build(int &u,int v,int l,int r,int val) {if (!u) u=++sz;if (l==r) {tr[u].s=tr[v].s+1;return;}int mid=(l+r)>>1;if (val<=mid) build(tr[u][0],tr[v][0],l,mid,val),tr[u][1]=tr[v][1];else build(tr[u][1],tr[v][1],mid+1,r,val),tr[u][0]=tr[v][0];tr[u].s=tr[tr[u][0]].s+tr[tr[u][1]].s;}int query(int u,int v,int l,int r,int ql,int qr) {if (!u && !v) return 0;if (l==ql && r==qr) return tr[v].s-tr[u].s;int mid=(l+r)>>1;if (qr<=mid) return query(tr[u][0],tr[v][0],l,mid,ql,qr);else if (ql>mid) return query(tr[u][1],tr[v][1],mid+1,r,ql,qr);else return query(tr[u][0],tr[v][0],l,mid,ql,mid)+query(tr[u][1],tr[v][1],mid+1,r,mid+1,qr);}
}
using namespace Chairtree;int main() {scanf("%d%d%d%d",&n,&m,&Q,&T);LCT::main();for (int i=1;i<=m;i++) build(rt[i],rt[i-1],0,m,ntr[i]);for (int l,r,i=1;i<=Q;i++) {scanf("%d%d",&l,&r);if (T) l^=ans,r^=ans;ans=n-query(rt[l-1],rt[r],0,m,0,l-1);printf("%d\n",ans);}return 0;
}

转载于:https://www.cnblogs.com/MashiroSky/p/6484381.html

【bzoj3514】 Codechef MARCH14 GERALD07加强版相关推荐

  1. BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT维护最大生成树 主席树

    题面 考虑没有询问,直接给你一个图问联通块怎么做. 并查集是吧. 现在想要动态地做,那么应该要用LCT. 考虑新加进来一条边,想要让它能够减少一个联通块的条件就是现在边的两个端点还没有联通. 如果联通 ...

  2. bzoj3514: Codechef MARCH14 GERALD07加强版

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3514 思路:这题思路很巧妙 首先每个连通块只要保留一棵生成树的边就可以保证连通了 把每条边的 ...

  3. 【BZOJ3514】Codechef MARCH14 GERALD07加强版 LCT+主席树

    [BZOJ3514]Codechef MARCH14 GERALD07加强版 Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行 ...

  4. 【洛谷P5385】须臾幻境/【BZOJ3514】Codechef MARCH14 GERALD07加强版【LCT】【主席树】

    题意:有nnn个点mmm条边,qqq次询问连接区间[L,R][L,R][L,R]中的边后的连通块个数.强制在线. n,m,q≤2×105n,m,q\leq 2\times10^5n,m,q≤2×105 ...

  5. 【BZOJ3514】Codechef MARCH14 GERALD07加强版,LCT+主席树

    Time:2016.08.06 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 今天模拟题T3 结果是看都没看?? n,m<=1000 每次直接暴力并查集,O(n)判断 复杂度 ...

  6. BZOJ 3514 Codechef MARCH14 GERALD07加强版

    从CC抠的题 xyz大神直接用分块秒 虽然会MLE+TLE 时限被改成40s了,我觉得30s足够了吧-- 考虑从左至右加入每一条边,加入某条边成环的环那么这条边对答案就没有影响.那么只要环上标号最小的 ...

  7. 2017.10.17 Codechef MARCH14 GERALD07加强版 失败总结

    以前做这个题简直是噩梦的难度 有个很神的做法就是 利用最简联通形式来统计联通块 把一个要求的区间写成一颗等价的树,,就有了统一的标准 然后考虑怎么构造这棵树,看每次加入的边,如果已经联通,则考虑把这个 ...

  8. BZOJ 3514 Codechef MARCH14 GERALD07 加强版 LCT+主席树

    题意: N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 分析: 据说有dalao会离线做这题? 看到L和R就能想到主席树?dalao们太强了-- 如果我们给出n个点,m ...

  9. BZOJ3514:GERALD07加强版(LCT,主席树)

    Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密. 接下来 ...

最新文章

  1. PYTHON自动化Day12-unittest自动注册登录
  2. 2016/12summary
  3. python 什么是上下文管理器(ContextManager)?
  4. 【docker】修改docker容器配置,设置/修改端口映射
  5. ELK学习笔记之Logstash详解
  6. 链表插入功能实现演示
  7. 阿里二面差点败在这道题:MySQL自增主键为何不是连续的呢?
  8. electron 渲染进程调用主进程_万物皆可快速上手之Electron(第一弹)
  9. 使用Stanford NLP software进行中文文本预处理
  10. 59. 预定义超全局变量
  11. java实现蒙特卡洛树搜索_面试必会:java实现 BST 二叉查询树详解
  12. 思科ccna教材_什么是CCNA或Cisco认证网络助理?
  13. word中插入对号、错号符号
  14. 计算机机房普通照明,计算机机房对照明的要求
  15. arm汇编指令中MRS和MSR
  16. 微信群影视机器人登录使用教程
  17. signature=cb30417dfa65eef445418827e0f0e0e6,以太坊P2P网络节点初始化
  18. WTD实验(lv9-day15)
  19. 冯唐:成大事者,必经的3个阶段
  20. python爬虫 爬取360图片(非结构化数据)

热门文章

  1. 如何保持连接_工高连城 | 连接器连接失效的原因有哪些
  2. remmina连接xfce桌面的centos7
  3. matplotlib 的一些知识
  4. 蓄水池抽样算法 Reservoir Sampling
  5. Java randomString
  6. 写出gradle风格的groovy代码
  7. Python学习笔记——基础篇【第七周】———FTP作业(面向对象编程进阶 Socket编程基础)...
  8. ADO连接各种数据库
  9. vs/c++缓冲区溢出,未初始化变量检查
  10. [导入][你必须知道的.NET]第十回:品味类型---值类型与引用类型(下)-应用征途...