题目大意:

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

题解:

这道题考试的时候没想出来

于是便爆炸

结果今天下午拿出昨天准备的题表准备做题的时候

题表里就有这题..

欲哭无泪啊有木有... ...


  • 说正经的

假设我们可以做到用并查集实现区间减法

那么很显然的做法就是维护前缀并查集然后做差

但是并查集并不满足区间减法.

但是我们可以考虑一下如果并查集满足区间减法,那我们会拿它做什么

我们对并查集做差实际上就是想使并查集\([1,R]\)退回到删除掉\([1,L-1]\)区间内的边的状态

这什么玩意 ?? 这也能搞 ???

上面的思路都是考虑一个区间内有多少边对这个答案造成了影响.

我们反过来考虑,考虑一下每条边会影响哪些答案

我们想象一下并查集维护的过程及其对答案的影响:

每次加入一条边,如果边的两端未连通,那么直接连接两点,那么对所有包括了这个点的区间都一定会使这个区间的答案-1.我们定义此影响的起始端点为0.

如果两条点已经连通,由于我们已经计算过之前连通这两个点的边对答案的贡献了(贡献一定由编号最小的边做出).所以我们知道这条边对答案造成影响当且仅当这个区间不包括编号最小的边且包括当前的边.所以定义此影响的起始端点为最小边的编号.

为了使下一次操作依然正确,我们将找到的编号最小的边删除,并将当前边加入.不难发现这样是正确的.

所以我们只要求出某个区间中影响答案的起始端点小于询问端点的边的数目即可。

至于后面的这个操作可以用可持久化线段树维护

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 200010;
const int inf = 0x3f3f3f3f;
namespace lct{
struct Node{
Node *ch[2],*fa;
int mn,w,tag;
inline void update();
inline void push_down();
}*null;
Node mem[maxn<<2],*it;
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null->fa = null;
null->mn = null->w = inf;null->tag = 0;
}
inline Node* newNode(int val){
Node *p = it++;p->w = p->mn = val;
p->ch[0] = p->ch[1] = p->fa = null;
p->tag = 0;return p;
}
inline void Node::update(){
mn = min(min(ch[0]->mn,ch[1]->mn),w);
}
inline void Node::push_down(){
if(this == null || tag == 0) return;
if(ch[0] != null) ch[0]->tag ^= 1;
if(ch[1] != null) ch[1]->tag ^= 1;
swap(ch[0],ch[1]);tag = 0;
}
inline void rotate(Node *p,Node *x){
int k = p == x->ch[1];
Node *y = p->ch[k^1],*z = x->fa;
if(z->ch[0] == x) z->ch[0] = p;
if(z->ch[1] == x) z->ch[1] = p;
if(y != null) y->fa = x;
p->fa = z;p->ch[k^1] = x;
x->fa = p;x->ch[k] = y;
x->update();p->update();
}
inline bool isroot(Node *p){
return (p == null) || (p->fa->ch[0] != p && p->fa->ch[1] != p);
}
inline void Splay(Node *p){
p->push_down();
while(!isroot(p)){
Node *x = p->fa,*y = x->fa;
y->push_down();x->push_down();p->push_down();
if(isroot(x)) rotate(p,x);
else if((x->ch[0] == p)^(y->ch[0] == x)) rotate(p,x),rotate(p,y);
else rotate(x,y),rotate(p,x);
}p->update();
}
inline Node* Access(Node *x){
for(Node *y = null;x != null;y=x,x=x->fa)
Splay(x),x->ch[1] = y,x->update();
}
inline void makeroot(Node *p){
Access(p);Splay(p);p->tag ^= 1;
}
inline void link(Node *x,Node *y){
makeroot(x);x->fa = y;
}
inline void cut(Node *x,Node *y){
makeroot(x);Access(y);Splay(y);
y->ch[0] = y->ch[0]->fa = null;
y->update();
}
inline Node* findroot(Node *x){
Access(x);Splay(x);
while(x->ch[0] != null) x = x->ch[0];
Splay(x);return x;
}
inline int query(Node *x,Node *y){
makeroot(x);Access(y);Splay(y);
return y->mn;
}
}
namespace seg{
struct Node{
Node* ch[2];
int num;
void update();
}*null;
Node mem[maxn*30],*it;
Node *root[maxn];
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null;
null->num = 0;root[0] = null;
}
inline void Node::update(){
num = ch[0]->num + ch[1]->num;
}
Node* insert(Node *rt,int l,int r,int pos){
Node *p = it++;(*p) = (*rt);
if(l == r){
p->num ++;
return p;
}
int mid = (l+r) >> 1;
if(pos <= mid) p->ch[0] = insert(p->ch[0],l,mid,pos);
else p->ch[1] = insert(p->ch[1],mid+1,r,pos);
p->num = p->ch[0]->num + p->ch[1]->num;
return p;
}
int query(Node *x,Node *y,int l,int r,int L,int R){
if(L <= l && r <= R) return y->num - x->num;
int mid = (l+r) >> 1;
if(R <= mid) return query(x->ch[0],y->ch[0],l,mid,L,R);
if(L > mid) return query(x->ch[1],y->ch[1],mid+1,r,L,R);
return query(x->ch[0],y->ch[0],l,mid,L,R) + query(x->ch[1],y->ch[1],mid+1,r,L,R);
}
}
lct::Node* mp[maxn];
struct Node{
int u,v;
}e[maxn];
int main(){
lct::init();seg::init();
int n,m,q,type;read(n);read(m);read(q);read(type);
for(int i=1;i<=n;++i) lct::newNode(inf);
for(int i=1;i<=m;++i){
mp[i] = lct::newNode(i);
read(e[i].u);read(e[i].v);
if( lct::findroot(lct::mem+e[i].u) != lct::findroot(lct::mem+e[i].v)){
lct::link(lct::mem+e[i].u,mp[i]);
lct::link(lct::mem+e[i].v,mp[i]);
seg::root[i] = seg::insert(seg::root[i-1],0,m,0);
}else if(e[i].u == e[i].v){
seg::root[i] = seg::insert(seg::root[i-1],0,m,m);
}else{
int x = lct::query(lct::mem+e[i].u,lct::mem+e[i].v);
seg::root[i] = seg::insert(seg::root[i-1],0,m,x);
lct::cut(mp[x],lct::mem+e[x].u);
lct::cut(mp[x],lct::mem+e[x].v);
lct::link(mp[i],lct::mem+e[i].u);
lct::link(mp[i],lct::mem+e[i].v);
}
}
int u,v,lastans = 0;
while(q--){
read(u);read(v);
if(type) u ^= lastans,v ^= lastans;
int x = seg::query(seg::root[u-1],seg::root[v],0,m,0,u-1);
printf("%d\n",lastans = (n - x));
}
getchar();getchar();
return 0;
}

bzoj 3514: GERALD07加强版 lct+可持久化线段树的更多相关文章

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

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

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

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

  3. BZOJ 3514 GERALD07加强版 (LCT+主席树)

    题目大意:给定n个点m条边无向图,每次询问求当图中有编号为[L,R]的边时,整个图的联通块个数,强制在线 神题!(发现好久以前的题解没有写完诶) 我们要求图中联通块的个数,似乎不可搞啊. 联通块个数= ...

  4. [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)

    [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...

  5. bzoj 3673&3674 可持久化并查集&加强版(可持久化线段树+启发式合并)

    CCZ在2015年8月25日也就是初三暑假要结束的时候就已经能切这种题了%%% 学习了另一种启发式合并的方法,按秩合并,也就是按树的深度合并,实际上是和按树的大小一个道理,但是感觉(至少在这题上)更好 ...

  6. 【XSY2528】道路建设 LCT 可持久化线段树

    题目描述 给你一个\(n\)个点\(m\)条边图,\(q\)个询问,每次问你边权在\([l,r]\)之间的边组成的最小生成树(森林)的边权和.强制在线. \(n,m,q\leq 100000\) 题解 ...

  7. BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)

    BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...

  8. BZOJ 3653: 谈笑风生(DFS序+可持久化线段树)

    首先嘛,还是太弱了,想了好久QAQ 然后,这道题么,明显就是求sigma(size[x]) (x是y的儿子且层树小于k) 然后就可以发现:把前n个节点按深度建可持久化线段树,就能用前缀和维护了 其实不 ...

  9. bzoj 4504: K个串 可持久化线段树+堆

    题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...

随机推荐

  1. Jmeter 02 JMeter体系结构

    1. Jmeter简介 2. Jmeter体系结构 3. Jmeter运行原理 4. Jmeter测试计划要素 5. Jmeter环境介绍 6. Jmeter与Loadrunner异同

  2. web.xml配置中的log4jRefreshInterval

    采用spring框架的项目如何使用log4j在spring中使用log4j,有些方便的地方, 1.动态的改变记录级别和策略,即修改log4j.properties,不需要重启web应用,这需要在web ...

  3. OLTP和OLAP

    1 OLTP和OLAP online transaction processing,联机事务处理.业务类系统主要供基层人员使用,进行一线业务操作,通常被称为联机事务处理. online analyti ...

  4. iOS UICollection 和UITableview新特性

    很详细优秀的博客: http://www.jianshu.com/p/e97780a24224 iOS10新特性总结 http://blog.csdn.net/yyacheng/article/det ...

  5. SQLServer将一个表内指定列的所有值插入另一个表

    insert into records_resolve_bak(resolve_save_addr,resolve_time,resolve_status) select  resolve_save_ ...

  6. wechat JS-SKD (getLoaction) 定位显示百度map

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  7. Apache Shiro 使用手册(三)Shiro 授权(转发:http://kdboy.iteye.com/blog/1155450)

    授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等. 一.授权的三要素 授权有着三 ...

  8. xpath取最后一个元素

    取xpath最后一个book元素 book[last()] 取xpath最后第二个book元素 book[last()-1]

  9. Data Structure Binary Tree: Iterative Postorder Traversal

    http://www.geeksforgeeks.org/iterative-postorder-traversal-using-stack/ #include <iostream> #i ...

  10. C# 半角?全角

    /// <summary> /// 将资料表中已修改的资料行数据去左右空格.全角转半角 /// </summary> public sealed class FieldFitS ...