博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ-3514】Codechef MARCH14 GERALD07加强版 LinkCutTree + 主席树
阅读量:5339 次
发布时间:2019-06-15

本文共 2731 字,大约阅读时间需要 9 分钟。

3514: Codechef MARCH14 GERALD07加强版

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 1288  Solved: 490
[][][]

Description

N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

Input

第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。

接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

Output

 K行每行一个整数代表该组询问的联通块个数。

Sample Input

3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2

Sample Output

2
1
3
1

HINT

对于100%的数据,1≤N、M、K≤200,000。

2016.2.26提高时限至60s

Source

Solution

这应该算是动态图问题吧?? 问了一下ShallWe,用LCT维护动态图问题的一种离线做法是维护一颗 时间最大生成树 ,所以这个也是一样。

思路非常的巧妙,首先维护一颗 时间最大生成树 ,按时间顺序加边。

设当前加边为$<u,v>$,如果$u$和$v$属于同一个联通块,则加入$<u,v>$必然会形成环,那么切掉这个环上的边权(时间)最小的边,连上这个边,记这个被切掉的边为$pop_{i}$

然后这个题要求联通块的个数,然后发现,对于$pop$存在一个性质:

对于一条边$x$,在边$x$和使边$x$被切的边$y$之间连上的边,是不会与使边$x$被切得边$y$出现环的,即如果$r>y>l>x$则$y$必然会使联通块-1

所以问题就可以转化为求$[l,r]$中$pop<l$的$pop$的个数,这个可以用主席树去维护,所以答案就是$N-sum$。

Code

#include
#include
#include
#include
#include
using namespace std;#define INF 0x3fffffff#define MAXN 400010inline int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f;}int N,M,K,T,last;struct EdgeNode{int u,v;}edge[MAXN];namespace LCT{ int fa[MAXN],son[MAXN][2],id[MAXN],tim[MAXN]; bool rev[MAXN]; inline void Init() {for (int i=1; i<=N; i++) id[i]=i,tim[i]=INF;} inline bool is_root(int x) {return !fa[x] || son[fa[x]][0]!=x&&son[fa[x]][1]!=x;} inline int Min(int x,int y) {return tim[x]
>1; if (val<=mid) Insert(l,mid,lson[now],lson[par],val); else Insert(mid+1,r,rson[now],rson[par],val); } inline int Query(int l,int r,int L,int R,int val) { if (r<=val) return sum[R]-sum[L]; int mid=(l+r)>>1; if (val<=mid) return Query(l,mid,lson[L],lson[R],val); else return Query(l,mid,lson[L],lson[R],val)+Query(mid+1,r,rson[L],rson[R],val); }}using namespace PrTree;int pop[MAXN];int main(){ N=read(),M=read(),K=read(),T=read(); for (int i=1; i<=M; i++) edge[i].u=read(),edge[i].v=read(); LCT::Init(); for (int i=1; i<=M; i++) { int u=edge[i].u,v=edge[i].v; if (u==v) {pop[i]=i; continue;} if (LCT::Find(u)==LCT::Find(v)) { pop[i]=LCT::Query(u,v); LCT::Cut(u,pop[i]); LCT::Cut(v,pop[i]); pop[i]-=N; } id[i+N]=i+N,tim[i+N]=i; LCT::Link(u,i+N); LCT::Link(v,i+N); }// for (int i=1; i<=M; i++) printf("%d ",pop[i]); puts(""); for (int i=1; i<=M; i++) PrTree::Insert(0,M,root[i],root[i-1],pop[i]); while (K--) { int L=read(),R=read(); if (T) L^=last,R^=last; printf("%d\n",last=N-Query(0,M,root[L-1],root[R],L-1)); } return 0;}

  

 

转载于:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6213784.html

你可能感兴趣的文章
在一个RAC集群中最多支持多少节点
查看>>
怎样把图片资源导入Dll,并且取出来? (转)
查看>>
网络协议 4 - 交换机与 VLAN:办公室太复杂,我要回学校
查看>>
介绍一个开源的在线管理SQLServer的小工具--SQLEntMan
查看>>
展示博客
查看>>
课堂练习之“寻找水王”
查看>>
css选择器及举例
查看>>
vue中怎么实现获取当前点击对象this
查看>>
hdu2084
查看>>
Android 读取SIM卡参数
查看>>
内存对齐 align
查看>>
jquery复选框
查看>>
数据表格控件 DataGridControl
查看>>
监听器
查看>>
hdu 1496(hash)
查看>>
【转】qt ,使用tcp/ip协议网络传输数据时,字节序转换方法
查看>>
notes
查看>>
策略模式
查看>>
Linux查看硬件信息命令
查看>>
What's New in the .NET Framework 4
查看>>