[BZOJ3514] Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES)

题意

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

部分数据强制在线.

\(1\le N,M,K\le200,000\)

题解

有点意思的LCT题.

原题好像不强制在线于是可以回滚莫队+带撤销并查集水过去.

我们考虑暴力: 把 \([l,r]\) 内的所有点依次加入并查集, 每次若成功合并两个联通块则将答案 \(-1\).

在这种情况下, 一条边会在什么情况下对答案作出什么贡献? 显然是当两条边连接的两个点在左边的合法边都连过之后依然不联通的情况下会造成答案减少 \(1\).

考虑快速计算上面的贡献. 容易发现对于某条边 \(e\), 依次将它左侧的边加入图中, 一旦在某个边 \(e'\) 加入后 \(e\) 两边的点已经被联通, 那么继续加下去一定也是联通的. 又因为查询是将一整段区间的边加入图中, 所以一旦 \(e\) 和 \(e'\) 都被查询区间包含, 则 \(e\) 不会对答案作出贡献. 否则一定会对答案造成贡献.

于是只要我们对于所有 \(e\) 都预处理出 \(e'\) 的位置, 我们就可以通过查询 \([l,r]\) 内小于 \(l\) 的值的个数解决. 这个问题显然主席树/分块均可解决.

至于预处理, 我们可以使用LCT. 过程类似于水管局长. 从左到右依次加边, 如果加入边 \((u,v)\) 时出环了, 那么树上从 \(u\) 到 \(v\) 的路径上最早加入的边就是我们要求的. Splay上维护一下代表边的点的位置就好了(边权转点权的普通操作, 加点)

以及好像把点断掉的时候并不用存这个点代表的边是什么...把这个点Splay到根然后把左右子树直接断掉就好了...

以及黄学长&wulala的变量名真的是生动形象

参考代码

#include <bits/stdc++.h>
#define _O0 __attribute__((optimize("O0"))) const int MAXN=200010; struct LCT{
#define lch chd[0]
#define rch chd[1]
#define kch chd[k]
#define xch chd[k^1]
struct Node{
int val;
bool rev;
Node* prt;
Node* min;
Node* chd[2];
Node(int val):val(val),rev(false),prt(NULL),min(this),chd{NULL,NULL}{}
inline bool isRoot(){
return this->prt==NULL||(this->prt->lch!=this&&this->prt->rch!=this);
}
inline _O0 void Flip(){
if(this!=NULL){
std::swap(this->lch,this->rch);
this->rev=!this->rev;
}
}
inline void PushDown(){
if(this->rev){
this->lch->Flip();
this->rch->Flip();
this->rev=false;
}
}
inline void Maintain(){
this->min=this;
if(this->lch&&this->lch->min->val<this->min->val)
this->min=this->lch->min;
if(this->rch&&this->rch->min->val<this->min->val)
this->min=this->rch->min;
}
};
std::vector<Node*> N;
LCT(int n):N(n+1){
for(int i=1;i<=n;i++)
N[i]=new Node(INT_MAX);
}
void Rotate(Node* root,int k){
Node* tmp=root->xch;
root->PushDown();
tmp->PushDown();
tmp->prt=root->prt;
if(!root->isRoot()){
if(root->prt->lch==root)
root->prt->lch=tmp;
else
root->prt->rch=tmp;
}
root->xch=tmp->kch;
if(root->xch)
root->xch->prt=root;
tmp->kch=root;
root->prt=tmp;
root->Maintain();
tmp->Maintain();
} void Splay(Node* root){
while(!root->isRoot()){
int k=root->prt->lch==root;
if(root->prt->isRoot())
Rotate(root->prt,k);
else{
int d=root->prt->prt->lch==root->prt;
Rotate(k==d?root->prt->prt:root->prt,k);
Rotate(root->prt,d);
}
}
} void Expose(Node* root){
Splay(root);
root->PushDown();
if(root->rch){
root->rch=NULL;
root->Maintain();
}
} void Access(Node* root){
Expose(root);
Splay(root);
while(root->prt){
Splay(root->prt);
root->prt->PushDown();
root->prt->rch=root;
root->prt->Maintain();
Splay(root);
}
} void Evert(Node* root){
Access(root);
root->Flip();
} Node* FindRoot(Node* root){
Access(root);
Node* ans=root;
ans->PushDown();
while(ans->lch){
ans->PushDown();
ans=ans->lch;
}
Splay(ans);
return ans;
} void Link(Node* a,Node* b){
Evert(b);
b->prt=a;
} void Cut(Node* a,Node* b){
Evert(a);
Access(b);
b->PushDown();
b->lch->prt=NULL;
b->lch=NULL;
b->Maintain();
} int AddEdge(int a,int b,int val){
if(a==b)
return val;
int ret=0;
if(FindRoot(N[a])==FindRoot(N[b])){
Evert(N[a]);
Access(N[b]);
Node* min=N[b]->min;
ret=N[b]->min->val;
Splay(min);
min->lch->prt=NULL;
min->rch->prt=NULL;
}
N.push_back(new Node(val));
Link(*N.rbegin(),N[a]);
Link(*N.rbegin(),N[b]);
return ret;
}
#undef lch
#undef rch
#undef kch
#undef xch
}; struct SegTree{
struct Node{
int l;
int r;
int sum;
Node* lch;
Node* rch;
Node(int l,int r):l(l),r(r),sum(0),lch(NULL),rch(NULL){
if(l!=r){
int mid=(l+r)>>1;
this->lch=new Node(l,mid);
this->rch=new Node(mid+1,r);
}
}
Node(Node* ptr){
*this=*ptr;
}
void Insert(int x){
++this->sum;
if(l!=r){
if(x<=this->lch->r)
(this->lch=new Node(this->lch))->Insert(x);
else
(this->rch=new Node(this->rch))->Insert(x);
}
}
};
std::vector<Node*> N;
SegTree(int n){
N.push_back(new Node(0,n));
}
void Insert(int x){
N.push_back(new Node(*N.rbegin()));
(*N.rbegin())->Insert(x);
}
int Query(int l,int r,int x){
return Query(N[l-1],N[r],x);
}
int Query(Node* aux,Node* root,int x){
if(0<=root->l&&root->r<=x)
return root->sum-aux->sum;
else{
int ans=0;
if(0<=root->lch->r)
ans+=Query(aux->lch,root->lch,x);
if(root->rch->l<=x)
ans+=Query(aux->rch,root->rch,x);
return ans;
}
}
}; int n,m,q,opt;
int lastans;
int ntr[MAXN]; int main(){
scanf("%d%d%d%d",&n,&m,&q,&opt);
LCT* lct=new LCT(n);
SegTree* T=new SegTree(m);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
ntr[i]=lct->AddEdge(a,b,i);
}
for(int i=1;i<=m;i++)
T->Insert(ntr[i]);
for(int i=0;i<q;i++){
int l,r;
scanf("%d%d",&l,&r);
l^=opt*lastans;
r^=opt*lastans;
printf("%d\n",lastans=n-T->Query(l,r,l-1));
}
return 0;
}

[BZOJ 3514]Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES)的更多相关文章

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

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

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

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

  3. BZOJ 3514 Codechef MARCH14 GERALD07加强版

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

  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加强版

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

  6. BZOJ 3514 Codechef MARCH14 GERALD07加强版 Link-Cut-Tree+划分树

    题目大意: 给定n个点m条边的无向图.求问当图中仅仅有[编号在[l,r]区间内]的边存在时图中的联通块个数 强制在线 注意联通块是指联通了就是同一块,不是Tarjan求的那种块 看到这题的那一刻我就想 ...

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

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

  8. 【BZOJ-3514】Codechef MARCH14 GERALD07加强版 LinkCutTree + 主席树

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

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

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

随机推荐

  1. 深入理解java集合框架之---------Linked集合 -----构造函数

    linked构造函数 1.LinkedList(): 构造一个空列表的集合 /** * 序列化 */ private static final long serialVersionUID = 1090 ...

  2. 多功能电子通讯录(涉及到了双向链表的使用,Linux文件编程等等)

    readme.txt //作为一个程序员,我们咋么能不写用户手册呢!MSP的我觉得用户体验是王道,苹果手机的用户体验的确不错!不过WP加油!我去,扯远了!赶紧看我的程序吧!  歡迎使用多功能電子通訊錄 ...

  3. git hub 建立公钥

    1.  执行 $ eval "$(ssh-agent -s)" 2. 增加 ssh $ ssh-add ~/.ssh/id_rsa 3. 复制 生成的key (执行下面命令后就相当 ...

  4. 【转载】在Angular 2/Typescript中声明全局变量的最佳方式是什么?

    问题详细描述 我想在Typescript语言中的Angular 2中声明一些全局可见的变量.最佳的实践方法是? 推荐的实现方法 这是最简单的解决方案,无需使用Service或Observer: 将全局 ...

  5. WordPress主题开发:主题初始化

    在最简单的情况下,一个WordPress主题由两个文件构成: index.php ------------------主模版 style.css  -------------------主样式表(注意 ...

  6. mysql8.0遇到删除外键的错误

    错误信息:Cannot drop index 'energy_type_id': needed in a foreign key constraint 创建device表的信息 CREATE TABL ...

  7. JAVA注释方式

    1.单行(single-line)注释    //…… 2.块(block)注释                /*……*/ 3.文档注释                      /**……*/

  8. [javaSE] IO流(对象序列化)

    写入 获取ObjectOutputStream对象,new出来,构造参数:FileOutputStream对象目标文件 调用ObjectOutputStream对象的writeObject()方法,参 ...

  9. 局域网内配置虚拟机的hostname

    一般上我们在局域网内访问,比如宿主机访问虚拟机的时候可以直接使用IP去访问,大多数情况下也都适用.但是对于有的情况,比如像新版的hbase的配置,它默认将localhost作为hbase.master ...

  10. uwsgi/uWSGI/WSGI简介

    参考文章 uWSGI是一个Web服务器,它实现了WSGI协议.uwsgi.http等协议.Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换.z WSGI是一种Web服务器网 ...