题目大意:

给定n个点m条边的无向图。求问当图中仅仅有【编号在[l,r]区间内】的边存在时图中的联通块个数 强制在线

注意联通块是指联通了就是同一块,不是Tarjan求的那种块

看到这题的那一刻我就想小便有木有0.0 这尼玛怎么做?可持久化并查集? 暴力? 分块乱搞? 。。。

后来看了HZWER大神的博客才知道这样的巧妙的算法0.0 太强大了

直接复制wulala的题解 讲得非常清楚 不累述了

wulala

葱娘说这是一个非常巧妙的题。。

有一个比較猎奇的做法:首先把边依次加到图中,若当前这条边与图中的边形成了环,那么把这个环中最早加进来的边弹出去

并将每条边把哪条边弹了出去记录下来:ntr[i] = j,特别地,要是没有弹出边,ntr[i] = 0;

这个显然是能够用LCT来弄的对吧。

然后对于每一个询问,我们的答案就是对l~r中ntr小于l的边求和,并用n减去这个值

正确性能够YY一下:

假设一条边的ntr >= l,那么显然他能够与从l ~ r中的边形成环,那么它对答案没有贡献

反之假设一条边的ntr < l那么它与从l ~ r中的边是不能形成环的。那么他对答案的贡献为-1

对于查询从l ~ r中有多少边的ntr小于l,我反正是用的函数式线段树

这个真是太强大了0.0 假设这条边踢掉的最早的边也在[l,r]区间内 那么增加这条边一定对图的连通性没有影响 否则就会连接两个联通块 导致ans--

至于求l~r中有多少边的ntr小于l我用的是划分树 蒟蒻不会写主席树肿莫破。。

ntr。寝取り,果然是个够劲的名字。

。 于是为了保持这样的美好的意境我也牺牲了划分树中的a数组改成了ntr。。

把这个美好的意境传承下去吧。。

另外这题有自环 自环的话相当于自己ntr自己 直接记录ntr之后就返回好了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 200200
#define INF 2147483647
using namespace std;
struct edges{
int x,y;
}e[M];
struct abcd{
abcd *fa,*ls,*rs;
int num,minnum;
bool rev_mark;
abcd(int x);
void Reverse();
void Push_Up();
void Push_Down();
}*null=new abcd(INF),*tree[M<<1];
abcd :: abcd(int x)
{
fa=ls=rs=null;
num=minnum=x;
rev_mark=0;
}
void abcd :: Reverse()
{
rev_mark^=1;
swap(ls,rs);
}
void abcd :: Push_Up()
{
minnum=min(ls->minnum,rs->minnum);
minnum=min(minnum,num);
}
void abcd :: Push_Down()
{
if(fa->ls==this||fa->rs==this)
fa->Push_Down();
if(rev_mark)
{
ls->Reverse();
rs->Reverse();
rev_mark=0;
}
}
void Zig(abcd *x)
{
abcd *y=x->fa;
y->ls=x->rs;
x->rs->fa=y;
x->rs=y;
x->fa=y->fa;
if(y==y->fa->ls)
y->fa->ls=x;
else if(y==y->fa->rs)
y->fa->rs=x;
y->fa=x;
y->Push_Up();
}
void Zag(abcd *x)
{
abcd *y=x->fa;
y->rs=x->ls;
x->ls->fa=y;
x->ls=y;
x->fa=y->fa;
if(y==y->fa->ls)
y->fa->ls=x;
else if(y==y->fa->rs)
y->fa->rs=x;
y->fa=x;
y->Push_Up();
}
void Splay(abcd *x)
{
x->Push_Down();
while(x->fa->ls==x||x->fa->rs==x)
{
abcd *y=x->fa,*z=y->fa;
if(x==y->ls)
{
if(y==z->ls)
Zig(y);
Zig(x);
}
else
{
if(y==z->rs)
Zag(y);
Zag(x);
}
}
x->Push_Up();
}
void Access(abcd *x)
{
abcd *y=null;
while(x!=null)
{
Splay(x);
x->rs=y;
x->Push_Up();
y=x;
x=x->fa;
}
}
abcd* Find_Root(abcd *x)
{
while(x->fa!=null)
x=x->fa;
return x;
}
void Move_To_Root(abcd *x)
{
Access(x);
Splay(x);
x->Reverse();
}
void Link(abcd *x,abcd *y)
{
Move_To_Root(x);
x->fa=y;
}
void Cut(abcd *x,abcd *y)
{
Move_To_Root(x);
Access(y);
Splay(y);
x->fa=null;
y->ls=null;
y->Push_Up();
}
int Query(abcd *x,abcd *y)
{
Move_To_Root(x);
Access(y);
Splay(y);
return y->minnum;
}
int n,m,q,type,ans;
int ntr[M],b[M],c[M],s[20][M];
void Insert(int p)
{
if(e[p].x==e[p].y)
{
ntr[p]=p;
return ;
}
abcd *x=tree[e[p].x],*y=tree[e[p].y];
if( Find_Root(x)==Find_Root(y) )
{
int temp=Query(x,y);
ntr[p]=temp;
Cut(tree[n+temp],tree[e[temp].x]);
Cut(tree[n+temp],tree[e[temp].y]);
free(tree[n+temp]);
}
tree[n+p]=new abcd(p);
Link(tree[n+p],tree[e[p].x]);
Link(tree[n+p],tree[e[p].y]);
}
void Build_Tree(int l,int r,int dpt)
{
int i,mid=l+r>>1;
int l1=l,l2=mid+1;
int left=mid-l+1;
if(l==r)
return ;
for(i=l;i<=r;i++)
left-=(ntr[i]<c[mid]);
for(i=l;i<=r;i++)
{
if(ntr[i]<c[mid]||ntr[i]==c[mid]&&left)
b[l1++]=ntr[i],s[dpt][i]=(i==l?1:s[dpt][i-1]+1),left-=(ntr[i]==c[mid]);
else
b[l2++]=ntr[i],s[dpt][i]=(i==l?0:s[dpt][i-1]);
}
memcpy( ntr+l , b+l , sizeof(ntr[0])*(r-l+1) );
Build_Tree(l,mid,dpt+1);
Build_Tree(mid+1,r,dpt+1);
}
int Get_Ans(int l,int r,int dpt,int x,int y,int val)
{
int mid=l+r>>1;
int l1=(x==l?0:s[dpt][x-1]),l2=s[dpt][y];
if(x>y)
return 0;
if(l==r)
return ntr[mid]<val;
if(val<=c[mid])
return Get_Ans(l,mid,dpt+1,l+l1,l+l2-1,val);
else
return l2-l1+Get_Ans(mid+1,r,dpt+1,(mid+1)+(x-l-l1),(mid+1)+(y-l+1-l2)-1,val);
}
int main()
{
int i,x,y;
cin>>n>>m>>q>>type;
for(i=1;i<=n;i++)
tree[i]=new abcd(INF);
for(i=1;i<=m;i++)
scanf("%d%d",&e[i].x,&e[i].y),Insert(i);
memcpy(c+1,ntr+1,sizeof(c[0])*m);
sort(c+1,c+m+1);
Build_Tree(1,m,0);
for(i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
x^=ans*type;y^=ans*type;
ans=n-Get_Ans(1,m,0,x,y,x);
printf("%d\n", ans );
}
}

BZOJ 3514 Codechef MARCH14 GERALD07加强版 Link-Cut-Tree+划分树的更多相关文章

  1. BZOJ 3514: Codechef MARCH14 GERALD07加强版 [LCT 主席树 kruskal]

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1312  Solved: 501 ...

  2. BZOJ 3514: Codechef MARCH14 GERALD07加强版( LCT + 主席树 )

    从左到右加边, 假如+的边e形成环, 那么记下这个环上最早加入的边_e, 当且仅当询问区间的左端点> _e加入的时间, e对答案有贡献(脑补一下). 然后一开始是N个连通块, 假如有x条边有贡献 ...

  3. [BZOJ 3514]Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES)

    [BZOJ3514] Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES) 题意 \(N\) 个点 \(M\) 条边的无向图,\(K\) 次询问保 ...

  4. BZOJ 3514: Codechef MARCH14 GERALD07加强版(LCT + 主席树)

    题意 \(N\) 个点 \(M\) 条边的无向图,询问保留图中编号在 \([l,r]\) 的边的时候图中的联通块个数. \(K\) 次询问强制在线. \(1\le N,M,K \le 200,000\ ...

  5. BZOJ 3514 Codechef MARCH14 GERALD07加强版

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3514 题意:给出一个图m条边.每次询问只加入编号在区间[L,R]之内的边有多少连通 ...

  6. 【刷题】BZOJ 3514 Codechef MARCH14 GERALD07加强版

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

  7. BZOJ 3514: Codechef MARCH14 GERALD07加强版 (LCT维护最大生成树+主席树)

    题意 给出nnn个点,mmm条边.多次询问,求编号在[l,r][l,r][l,r]内的边形成的联通块的数量,强制在线. 分析 LCTLCTLCT维护动态最大生成树,先将每条边依次加进去,若形成环就断掉 ...

  8. 【bzoj3514】Codechef MARCH14 GERALD07加强版 LCT+可持久化线段树

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

  9. BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT+可持久化线段树

    自己独自想出来并切掉还是很开心的~ Code: #include <bits/stdc++.h> #define N 400005 #define inf 1000000000 #defi ...

随机推荐

  1. poj3233Matrix Power Series(矩阵乘法)

    Matrix Power Series Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23187   Accepted: ...

  2. 【Python】循环语句

    while循环 当条件成立时,循环体的内容可以一直执行,但是避免死循环,需要有一个跳出循环的条件才行. for循环 遍历任何序列(列表和字符串)中的每一个元素 >>> a = [&q ...

  3. jorgchart,帮助你生成组织结构图的

    下载地址: http://yunpan.cn/c6pfenkmmFV2q  访问密码 8e29 演示链接: http://www.gbtags.com/gb/share/546.htm jstree. ...

  4. 5.26 Quartz任务调度图解2

  5. reduce多种方法计算数组中某个值的出现次数

    先来了解下reduce用法 arr.reduce(callback[, initialValue]) callback执行数组中每个值的函数,包含四个参数: accumulator 累计器累计回调的返 ...

  6. 通过Web Service实现IP地址查询功能

    实例01 实现一个简单的Web服务访问 本实例将实现IP地址查询接口服务,根据用户传入的IP地址返回IP所在的省.市.地区,实例中将会用到IP地址库用于查询信息,由于数据较多,所以读者可在光盘资源文件 ...

  7. 使用Ajax验证用户名

    Ajax是一项很重要的技术,下面简要举个例子,来解释如何使用Ajax.步骤如下:使用Ajax验证用户名使用文本框的onBlur事件 使用Ajax技术实现异步交互创建XMLHttpRequest对象通过 ...

  8. 浅谈Java三大框架与应用

    前言:对于一个程序员来说,尤其是在java web端开发的程序员,三大框架:Struts+Hibernate+Spring是必须要掌握熟透的,因此,下面谈谈java三大框架的基本概念和原理. JAVA ...

  9. 07--c++类的构造函数详解

    c++类的构造函数详解 c++构造函数的知识在各种c++教材上已有介绍,不过初学者往往不太注意观察和总结其中各种构造函数的特点和用法,故在此我根据自己的c++编程经验总结了一下c++中各种构造函数的特 ...

  10. Generics of a Higher Kind

    http://adriaanm.github.io/files/higher.pdf https://www.atlassian.com/blog/archives/scala-types-of-a- ...