[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 ...
随机推荐
- [心平气和读经典]The TCP/IP Guide(001)
The TCP/IP Guide[Page 40,41] Introduction To the TCP/IP Guide | TCP/IP指南概述 As I sit here writing thi ...
- MySQL数据库-错误1166 - Incorrect column name 'xxx' 的解决方法
在用Navicat for MySQL给MySQL数据库修改表的字段时报如下的错误: 解决方法:检查字段里面是不是有空格,去掉就可以了.
- SVD总结
1.概述 我们先从实数域R开始说起,再延伸到复数域C上去,先列出一个表格,把实数域以及复数域中常见的矩阵及其性质概括如下: 表1 常见矩阵及其性质 我们知道实对称矩阵正交相似于对角阵,从而将一个方阵对 ...
- 十二:video 视频
属性名 类型 默认值 说明 src String 要播放视频的资源地址 controls Boolean true 是否显示默认播放控件(播放/暂停按钮.播放进度.时间) danmu-list O ...
- php常用的时间函数
测试环境:php5.3.29 unix时间戳(从Unix 纪元(January 1 1970 00:00:00 GMT)到给定时间的秒数.).以下简称时间戳. 设置默认时区 date_default_ ...
- 判断php变量是否定义,是否为空,是否为真的一览表
分类: 使用 PHP 函数对变量 $x 进行比较 表达式 gettype() empty() is_null() isset() boolean : if($x) $x = ""; ...
- Maven环境的搭建
1.本地仓库和apache-mavenbin.zip的下载与解压 <1.apache-mavenbin.zip下载网址 http://maven.apache.org/download.cgi ...
- fzou 1759 Super A^B mod C
Problem 1759 Super A^B mod CAccept: 456 Submit: 1488Time Limit: 1000 mSec Memory Limit : 32768 ...
- Luogu 4240:毒瘤之神的考验
传送门 Sol 分开考虑 \(\varphi(ij)\) 中 \(ij\) 的质因子 那么 \[\varphi(ij)=\frac{\varphi(i)\varphi(j)gcd(i,j)}{\var ...
- redux、immutablejs和mobx性能对比(二)
三.分析数据 1.前提说明 我对测试出的10个数据摘除最大值与最小值,然后求平均值 根据平均值我绘制了一个曲线图一个柱状图 曲线图用于查看1000-100000的性能趋势 柱状图用于比较在相同条数下r ...