BZOJ 3514 Codechef MARCH14 GERALD07 加强版 LCT+主席树
题意:
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
分析:
据说有dalao会离线做这题?
看到L和R就能想到主席树?dalao们太强了……
如果我们给出n个点,m条边,求整张图的联通块个数,那么可以维护一个并查集,假如合并了p次,那么最终结果就是n-p。
但是,如果求保留[L,R]这些边图中的联通块个数怎么办?因为边的序号是有序的,所以我们肯定是要把边一次连入图中的。
设我们新要加入的某条边两端点是x和y,可能我们加入这第i条边时,x和y已经连通,那么我们可以将x到y链上最早加入的一条边删除,假设删除的那条边序号为j,那么我们令p[i]=j,当然,如果x和y原本不连通的话,p[i]=0。
为什么要求这个呢。我们发现,对于存在于L到R区间内的边i,所有的i不大于L-1的p[i],对答案的贡献都是-1(包括p[i]==0的情况)。为什么呢? 我们可以看到,如果在这个区间内p[i]<L,则相当于这条边的假如使两个原本不连通的点连通了起来,或是之前连通但是维系两个点连通的边不在这个区间内(等同于加边时被替掉了),即对答案是有贡献的,但如果L<=p[i]<=R,则相当于这个区间内的边自己人和自己人形成了环,那么对答案不会造成贡献,所以我们答案是正确的,有几个满足要求的p[i],就用n减去几即可。
这个过程听起来并不复杂,但是,怎样维护,怎样在合适的时间复杂度内求出解成了我们面临的问题。
加边删边操作用LCT显然可以解决。但是求L到R内p[i]不超过L-1的边的数量怎么办,我们可以用主席树对吧,毕竟这相当于建n棵彼此相似的线段树,只要用到前缀和的思想即可(就像区间k大那样就好)。
代码:
![](/assets/blank.gif)
![](/assets/blank.gif)
1 #include<bits/stdc++.h> 2 #define lc(x) t[x][0] 3 #define rc(x) t[x][1] 4 using namespace std; 5 const int N=400005; 6 struct node{int x,y;}e[N*2]; 7 struct LCT{ 8 int t[N][2],s[N],rev[N],fa[N],v[N],mn[N],tp; 9 void init(){memset(v,0x3f,sizeof(v));} 10 void pushup(int x){ 11 int l=lc(x),r=rc(x);mn[x]=x; 12 if(v[mn[l]]<v[mn[x]]) mn[x]=mn[l]; 13 if(v[mn[r]]<v[mn[x]]) mn[x]=mn[r]; 14 } bool pdrt(int x){ 15 return rc(fa[x])!=x&&lc(fa[x])!=x; 16 } void revers(int x){ 17 rev[x]^=1;swap(lc(x),rc(x)); 18 } void pushdown(int x){ 19 if(rev[x]){rev[x]=0; 20 if(lc(x)) revers(lc(x)); 21 if(rc(x)) revers(rc(x)); 22 } return ; 23 } void rotate(int x){ 24 int y=fa[x];int z=fa[y]; 25 int dy=(rc(y)==x),dz=(rc(z)==y); 26 if(!pdrt(y)) t[z][dz]=x; 27 t[y][dy]=t[x][dy^1];fa[t[y][dy]]=y; 28 t[x][dy^1]=y;fa[y]=x;fa[x]=z; 29 pushup(x);pushup(y); 30 } void splay(int x){ 31 s[++tp]=x; 32 for(int i=x;!pdrt(i);i=fa[i]) 33 s[++tp]=fa[i]; 34 while(tp) pushdown(s[tp--]); 35 while(!pdrt(x)){ 36 int y=fa[x];int z=fa[y]; 37 if(!pdrt(y)) 38 if(rc(y)==x^rc(z)==y) rotate(x); 39 else rotate(y);rotate(x); 40 } pushup(x);return ; 41 } void access(int x){ 42 for(int i=0;x;x=fa[x]) 43 splay(x),rc(x)=i,i=x; 44 } void mkrt(int x){ 45 access(x);splay(x);revers(x); 46 } int fdrt(int x){ 47 access(x);splay(x); 48 while(lc(x)) pushdown(x),x=lc(x); 49 return x; 50 } void split(int x,int y){ 51 mkrt(x);access(y);splay(y); 52 } void link(int x,int y){ 53 mkrt(x);if(fdrt(y)!=x) fa[x]=y; 54 } void cut(int x,int y){ 55 mkrt(x); 56 if(fdrt(y)==x&&fa[x]==y&&!rc(x)) 57 fa[x]=lc(y)=0;pushup(y); 58 } int ask(int x,int y){ 59 split(x,y);return mn[y]; 60 } 61 } lct;int rt[N],cnt=0,n,m,tp,q,ans=0; 62 struct ch{int l,r,sm;}t[N*20];int p[N]; 63 int update(int cur,int fa,int l,int r,int p){ 64 cur=++cnt;t[cur]=t[fa]; 65 t[cur].sm++;if(l==r) return cur; 66 int mid=l+r>>1; 67 if(p<=mid) t[cur].l= 68 update(t[cur].l,t[fa].l,l,mid,p); 69 else t[cur].r= 70 update(t[cur].r,t[fa].r,mid+1,r,p); 71 return cur; 72 } int query(int x,int y,int l,int r,int v){ 73 if(r==v) return t[y].sm-t[x].sm; 74 int mid=l+r>>1; 75 if(v<=mid) 76 return query(t[x].l,t[y].l,l,mid,v); 77 else return t[t[y].l].sm-t[t[x].l].sm+ 78 query(t[x].r,t[y].r,mid+1,r,v); 79 } void pre(){ 80 int num=n; 81 for(int i=1;i<=m;i++){ 82 int x=e[i].x,y=e[i].y; 83 if(x==y){p[i]=i;continue;} 84 if(lct.fdrt(x)==lct.fdrt(y)){ 85 int u=lct.ask(x,y); 86 int v=lct.v[u];p[i]=v; 87 lct.cut(e[v].x,u); 88 lct.cut(e[v].y,u); 89 } lct.v[++num]=i;lct.mn[num]=num; 90 lct.link(x,num);lct.link(y,num); 91 } for(int i=1;i<=m;i++) 92 rt[i]=update(rt[i],rt[i-1],0,m,p[i]); 93 } void solve(int x,int y){ 94 if(tp==1) x^=ans,y^=ans; 95 ans=n-query(rt[x-1],rt[y],0,m,x-1); 96 printf("%d\n",ans); 97 } int main(){ 98 lct.init(); 99 scanf("%d%d%d%d",&n,&m,&q,&tp); 100 for(int i=1;i<=n+m;i++) lct.mn[i]=i; 101 for(int i=1;i<=m;i++) 102 scanf("%d%d",&e[i].x,&e[i].y);pre(); 103 for(int i=1,x,y;i<=q;i++) 104 scanf("%d%d",&x,&y),solve(x,y);return 0; 105 }
LCT+主席树
转载于:https://www.cnblogs.com/Alan-Luo/articles/10158613.html
BZOJ 3514 Codechef MARCH14 GERALD07 加强版 LCT+主席树相关推荐
- 【BZOJ3514】Codechef MARCH14 GERALD07加强版 LCT+主席树
[BZOJ3514]Codechef MARCH14 GERALD07加强版 Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行 ...
- BZOJ 3514 Codechef MARCH14 GERALD07加强版
从CC抠的题 xyz大神直接用分块秒 虽然会MLE+TLE 时限被改成40s了,我觉得30s足够了吧-- 考虑从左至右加入每一条边,加入某条边成环的环那么这条边对答案就没有影响.那么只要环上标号最小的 ...
- BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT维护最大生成树 主席树
题面 考虑没有询问,直接给你一个图问联通块怎么做. 并查集是吧. 现在想要动态地做,那么应该要用LCT. 考虑新加进来一条边,想要让它能够减少一个联通块的条件就是现在边的两个端点还没有联通. 如果联通 ...
- BZOJ3514:GERALD07加强版(LCT,主席树)
Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密. 接下来 ...
- 【洛谷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 ...
- 【BZOJ3514】Codechef MARCH14 GERALD07加强版,LCT+主席树
Time:2016.08.06 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 今天模拟题T3 结果是看都没看?? n,m<=1000 每次直接暴力并查集,O(n)判断 复杂度 ...
- 【bzoj3514】 Codechef MARCH14 GERALD07加强版
http://www.lydsy.com/JudgeOnline/problem.php?id=3514 (题目链接) 题意 给出$n$个点$m$条边的无向图,询问保留图中编号在$[l,r]$的边的时 ...
- 2017.10.17 Codechef MARCH14 GERALD07加强版 失败总结
以前做这个题简直是噩梦的难度 有个很神的做法就是 利用最简联通形式来统计联通块 把一个要求的区间写成一颗等价的树,,就有了统一的标准 然后考虑怎么构造这棵树,看每次加入的边,如果已经联通,则考虑把这个 ...
- bzoj3514: Codechef MARCH14 GERALD07加强版
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3514 思路:这题思路很巧妙 首先每个连通块只要保留一棵生成树的边就可以保证连通了 把每条边的 ...
最新文章
- pyWavelets工具包的安装及使用
- 在IIS7中应用Application Request Routing配置反向代理
- P2668 斗地主 dp+深搜版
- matlab图片拼接变成白的,利用matlab实现对图片的拼接
- openshift使用_OpenShift v3:使用WildFly和MySQL的Java EE 7入门
- Fedora 19 Mate环境安装Gnome3
- 让你的单细胞数据动起来!|iCellR(一)
- APP引导页UI设计素材模板|轻松留下完美的第一印象
- 性能测试之JMeter中ForEach控制器详解
- 微软2月修复99个漏洞,含1个 0day
- bum报文_Vxlan学习笔记——原理
- Java常用api和操作必背
- 1003 我要通过! (20 分)—PAT (Basic Level) Practice (中文)
- Word 2016问题导致无法创建其他博客账号
- linux安装vmd软件步骤,VMD软件使用指南.PDF
- 我是如何写出一本畅销技术书的
- JavaScript下载后端返回的文件流
- 电压的符号代表的是什么意思
- php 会议室源码,PHP和jQuery实现会议排座管理.doc
- VS2017编译SQLite3生成.lib