[BZOJ 3514]Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES)
[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)的更多相关文章
- BZOJ 3514: Codechef MARCH14 GERALD07加强版( LCT + 主席树 )
从左到右加边, 假如+的边e形成环, 那么记下这个环上最早加入的边_e, 当且仅当询问区间的左端点> _e加入的时间, e对答案有贡献(脑补一下). 然后一开始是N个连通块, 假如有x条边有贡献 ...
- BZOJ 3514: Codechef MARCH14 GERALD07加强版 [LCT 主席树 kruskal]
3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1312 Solved: 501 ...
- BZOJ 3514 Codechef MARCH14 GERALD07加强版
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3514 题意:给出一个图m条边.每次询问只加入编号在区间[L,R]之内的边有多少连通 ...
- BZOJ 3514: Codechef MARCH14 GERALD07加强版(LCT + 主席树)
题意 \(N\) 个点 \(M\) 条边的无向图,询问保留图中编号在 \([l,r]\) 的边的时候图中的联通块个数. \(K\) 次询问强制在线. \(1\le N,M,K \le 200,000\ ...
- 【刷题】BZOJ 3514 Codechef MARCH14 GERALD07加强版
Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密. 接下来 ...
- BZOJ 3514 Codechef MARCH14 GERALD07加强版 Link-Cut-Tree+划分树
题目大意: 给定n个点m条边的无向图.求问当图中仅仅有[编号在[l,r]区间内]的边存在时图中的联通块个数 强制在线 注意联通块是指联通了就是同一块,不是Tarjan求的那种块 看到这题的那一刻我就想 ...
- BZOJ 3514: Codechef MARCH14 GERALD07加强版 (LCT维护最大生成树+主席树)
题意 给出nnn个点,mmm条边.多次询问,求编号在[l,r][l,r][l,r]内的边形成的联通块的数量,强制在线. 分析 LCTLCTLCT维护动态最大生成树,先将每条边依次加进去,若形成环就断掉 ...
- 【BZOJ-3514】Codechef MARCH14 GERALD07加强版 LinkCutTree + 主席树
3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1288 Solved: 490 ...
- 【LCT+主席树】BZOJ3514 Codechef MARCH14 GERALD07加强版
3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 2023 Solved: 778 ...
随机推荐
- APU (美国AMD公司研发的加速处理器)
APU(Accelerated Processing Unit)中文名字叫加速处理器,是AMD“融聚未来”理念的产品,它第一次将中央处理器和独显核心做在一个晶片上,它同时具有高性能处理器和最新独立显卡 ...
- SharePoint如何创建能够继承站点左面导航(Left Navigation)的Web Part页面
转自:http://social.msdn.microsoft.com/Forums/zh-CN/b069e6f8-e4d5-4bf3-93a1-4eecb55489d6/sharepointleft ...
- ASP.NET Core 集成 WebSocket
1. 环境 AspNetCore Web 2.0 (MVC) Windows 10 IIS 10 Express/IIS VS 2017 2.如何配置 在已有的或者新创建的 AspNet Core M ...
- 人脸识别(基于Caffe)
人脸识别(基于Caffe, 来自tyd) 人脸识别(判断是否为人脸) LMDB(数据库, 为Caffe支持的分类数据源) mkdir face_detect cd face_detect mkdir ...
- 深入了解javascript的sort方法
在javascript中,数组对象有一个有趣的方法 sort,它接收一个类型为函数的参数作为排序的依据.这意味着开发者只需要关注如何比较两个值的大小,而不用管“排序”这件事内部是如何实现的.不过了解一 ...
- developer.android.google.cn
Android Studio官方 Android IDE https://developer.android.google.cn/studio/index.html 探索 Android Studio ...
- 微信WeUI入门2
引入需要的样式文件 最重要的css文件为 weui.min.css 基本的框架如下: <!DOCTYPE html> <html lang="zh-CN"> ...
- ckeditor添加自定义按钮整合swfupload实现批量上传图片
ckeditor添加自定义按钮整合swfupload实现批量上传图片给ckeditor添加自定义按钮,由于ckeditor只能上传一张图片,如果要上传多张图片就要结合ckfinder,而ckfinde ...
- lvarchar类型对表结构变更影响
informix中lvarchar类型设计用于存储中度长度的字符数据(短的常用varchar类型.特别长的字符可用text类型).其默认长度2048byte,最大长度32739byte,是一种可变长度 ...
- Oracle数据库基本操作 (六) —— 数据的导出与导入
一.cmd 下登录oracle数据库下的指定用户 方式一:命令行明文连接登录 打开cmd,输入:sqlplus/nolog 输入:conn username/passworld@数据库实例名 方式二: ...