Portal --> CC Chef and Graph Queries

Solution

  快乐数据结构题(然而好像有十分优秀的莫队+可撤销并查集搞法qwq)

  首先考虑一种方式来方便一点地。。计算一个图的联通块数量:我们可以考虑容斥,维护每个连通块的生成树,然后\(n-\)生成树边数就是答案了

  这样有一个好,加边的时候比较好处理,但是光这样并不能解决我们的问题

​  顺着这个思路思考,先不考虑时间复杂度,对于一个询问,考虑将编号为\(l\sim r\)的边一条一条加入第\(1\sim l-1\)条边得到的生成树(们)中(先不考虑这个生成树边的选择方式),考虑一条边有贡献(成为新的生成树(们)中的一部分)的情况:

(1)这条边可以替换掉\(1\sim l-1\)中的某条边

(2)这条边的两个端点当前不连通

​  所以问题就变成了,看\(l\sim r\)中有多少条边可以替换掉在生成树中的编号在\(1\sim l-1\)范围内的边再加上(2)情况中的边

  这个时候,我们就可以确定生成树边的选择方式了:因为要让能替换掉在\(1\sim l-1\)范围内的边尽量多,所以一旦当前边可以替换掉另一条边,我们肯定优先选择编号小的替换

  再注意到在考虑询问\((l,r)\)的时候,我们其实相当于要得到\(1\sim r\)的生成树(们),于是我们就可以预处理,按顺序加边,用LCT维护当前的生成树(们),再用一棵主席树(按权值存)维护一下第\(1\sim i\)条边的生成树中,每个编号的边能被多少条编号更大的边替换掉,为了方便查询,那些不需要替换直接加入的边统一加到\(0\)的位置,然后查询的时候只要在第\(r\)棵和第\(l-1\)棵中查一下\([0,l-1]\)的和然后相减一下,再拿\(n\)减一下就是答案了

  最后还有一点就是。。因为要支持删边操作,所以LCT里面把边也看成一个点就好啦ovo

  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2*(1e5)+10,SEG=N*20,inf=2147483647;
int rec[N][2];
int n,m,Q,T;
namespace Lct{/*{{{*/
const int N=::N*2;
int ch[N][2],mn[N],fa[N],rev[N],val[N];
void reset(int x){
ch[x][0]=ch[x][1]=0; fa[x]=0; val[x]=mn[x]=inf;
}
void clear(int n){
for (int i=1;i<=n;++i) reset(i);
}
bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
int which(int x){return ch[fa[x]][1]==x;}
void reverse(int x){
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
void pushdown1(int x){
if (!rev[x]) return;
if (ch[x][0]) reverse(ch[x][0]);
if (ch[x][1]) reverse(ch[x][1]);
rev[x]=0;
}
void pushdown(int x){
if (!isroot(x)) pushdown(fa[x]);
pushdown1(x);
}
void pushup(int x){
mn[x]=val[x];
if (ch[x][0]) mn[x]=min(mn[x],mn[ch[x][0]]);
if (ch[x][1]) mn[x]=min(mn[x],mn[ch[x][1]]);
}
void rotate(int x){
int dir=which(x),f=fa[x];
if (!isroot(f)) ch[fa[f]][which(f)]=x;
fa[x]=fa[f]; fa[f]=x;
if (ch[x][dir^1]) fa[ch[x][dir^1]]=f;
ch[f][dir]=ch[x][dir^1];
ch[x][dir^1]=f;
pushup(f); pushup(x);
}
void splay(int x){
pushdown(x);
for (int f=fa[x];!isroot(x);f=fa[x]){
if (!isroot(f))
rotate(which(f)==which(x)?f:x);
rotate(x);
}
pushup(x);
}
void access(int x){
for (int last=0;x;last=x,x=fa[x]){
splay(x);
ch[x][1]=last;
pushup(x);
}
}
void make_rt(int x){
access(x);
splay(x);
reverse(x);
}
bool connected(int x,int y){
if (x==y) return true;
make_rt(x);
access(y);
splay(y);
return fa[x];
}
void link(int x,int y){
make_rt(x);
fa[x]=y;
access(x);
splay(x);
}
void cut(int x,int y){
make_rt(x);
access(y);
splay(y);
fa[x]=0;
ch[y][0]=0;
pushup(y);
}
int query(int x,int y){
make_rt(x);
access(y);
splay(y);
return mn[y];
}
}/*}}}*/
namespace Seg{/*{{{*/
int ch[SEG][2],sum[SEG],rt[SEG];
int n,tot;
void clear(){
for (int i=0;i<=tot;++i)
ch[i][0]=ch[i][1]=0,sum[i]=0;
tot=0;
}
void init(int _n){clear();n=_n;}
int newnode(int pre){
ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1]; sum[tot]=sum[pre];
return tot;
}
void _insert(int pre,int &x,int d,int lx,int rx){
x=newnode(pre);
++sum[x];
if (lx==rx) return;
int mid=lx+rx>>1;
if (d<=mid) _insert(ch[pre][0],ch[x][0],d,lx,mid);
else _insert(ch[pre][1],ch[x][1],d,mid+1,rx);
}
void insert(int pre,int x,int d){_insert(rt[pre],rt[x],d,1,n);}
int _query(int L,int R,int l,int r,int lx,int rx){
if (!L&&!R) return 0;
if (l<=lx&&rx<=r) return sum[R]-sum[L];
int mid=lx+rx>>1,ret=0;
if (l<=mid) ret+=_query(ch[L][0],ch[R][0],l,r,lx,mid);
if (r>mid) ret+=_query(ch[L][1],ch[R][1],l,r,mid+1,rx);
return ret;
}
int query(int L,int R,int l,int r){return _query(rt[L-1],rt[R],l,r,1,n);}
}/*}}}*/
void init(){
Lct::clear(n+m);
Seg::init(m+1);
}
void debug(int x){
printf("#%d:\n",x);
for (int i=0;i<=m;++i) printf("%d ",Seg::query(x-1,x,i+1,i+1));
printf("\n");
}
void solve(){
int x,y,tmp;
for (int i=1;i<=m;++i){
scanf("%d%d",&rec[i][0],&rec[i][1]);
x=rec[i][0]; y=rec[i][1];
if (x==y){
Seg::rt[i]=Seg::rt[i-1];
continue;
}
Lct::val[n+i]=i;
if (Lct::connected(x,y)){
tmp=Lct::query(x,y);
Lct::cut(rec[i][0],n+tmp);
Lct::cut(rec[i][1],n+tmp);
Lct::link(x,n+i);
Lct::link(y,n+i);
Seg::insert(i-1,i,tmp+1);
}
else{
Lct::link(x,n+i);
Lct::link(y,n+i);
Seg::insert(i-1,i,0+1);
}
//debug(i);
}
int l,r;
for (int i=1;i<=Q;++i){
scanf("%d%d",&l,&r);
printf("%d\n",n-Seg::query(l,r,0+1,(l-1)+1));
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&T);
for (int o=1;o<=T;++o){
scanf("%d%d%d",&n,&m,&Q);
init();
solve();
}
}

【CodeChef】Chef and Graph Queries的更多相关文章

  1. [CodeChef - GERALD07 ] Chef and Graph Queries

    Read problems statements in Mandarin Chineseand Russian. Problem Statement Chef has a undirected gra ...

  2. 【Codechef】Chef and Bike(二维多项式插值)

    something wrong with my new blog! I can't type matrixs so I come back. qwq 题目:https://www.codechef.c ...

  3. 【xsy2111】 【CODECHEF】Chef and Churus 分块+树状数组

    题目大意:给你一个长度为$n$的数列$a_i$,定义$f_i=\sum_{j=l_i}^{r_i} num_j$. 有$m$个操作: 操作1:询问一个区间$l,r$请你求出$\sum_{i=l}^{r ...

  4. [bzoj3514][CodeChef GERALD07] Chef ans Graph Queries [LCT+主席树]

    题面 bzoj上的强制在线版本 思路 首先可以确定,这类联通块相关的询问问题,都可以$LCT$+可持久化记录解决 用LCT维护生成树作为算法基础 具体而言,从前往后按照边的编号顺序扫一遍边 如果这条边 ...

  5. BZOJ3514 / Codechef GERALD07 Chef and Graph Queries LCT、主席树

    传送门--BZOJ 传送门--VJ 考虑使用LCT维护时间最大生成树,那么对于第\(i\)条边,其加入时可能会删去一条边.记\(pre_i\)表示删去的边的编号,如果不存在则\(pre_i = 0\) ...

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

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

  7. 【CodeChef】Querying on a Grid(分治,最短路)

    [CodeChef]Querying on a Grid(分治,最短路) 题面 Vjudge CodeChef 题解 考虑分治处理这个问题,每次取一个\(mid\),对于\(mid\)上的三个点构建最 ...

  8. 【CodeChef】Palindromeness(回文树)

    [CodeChef]Palindromeness(回文树) 题面 Vjudge CodeChef 中文版题面 题解 构建回文树,现在的问题就是要求出当前回文串节点的长度的一半的那个回文串所代表的节点 ...

  9. 【CodeChef】Find a special connected block - CONNECT(斯坦纳树)

    [CodeChef]Find a special connected block - CONNECT(斯坦纳树) 题面 Vjudge 题解 还是一样的套路题,把每个数字映射到\([0,K)\)的整数, ...

随机推荐

  1. JavaScript 中函数的参数

    functionName(parameter1, parameter2, parameter3) { // 要执行的代码…… } 参数规则 JavaScript 函数定义时形参没有指定数据类型. Ja ...

  2. Nginx快速入门

    本文主要介绍nginx的基本配置和操作,并介绍了一些可以完成的简单任务. 假设您已经学习过并已经安装好了nginx服务器. 如果没有,请参阅安装nginx页面(http://www.yiibai.co ...

  3. 华为笔试——C++进制转换

    题目:2-62进制转换 题目介绍:输入一个n1 进制的整数(包括负数),将其转换成n2 进制,其中n1 .n2 的范围是 [ 2,62 ] .每个数字的范围是0-9.a-z.A-Z.不用考虑非法输入. ...

  4. 获取label标签内for的属性值-js

    <body> <div class="row_2" id="ass"> <label for="aaa"> ...

  5. KETTLE设置变量

    一.kettle变量类型 kettle变量分为: 1.环境变量 通过 set variables组件设置变量,范围可以是:JVM变量.作业变量.父作业变量.根作业变量.使用时通过${var}或 %%v ...

  6. 分布式数据库中间件Mycat百亿级数据存储(转)

    此文转自: https://www.jianshu.com/p/9f1347ef75dd 2013年阿里的Cobar在社区使用过程中发现存在一些比较严重的问题,如高并发下的假死,心跳连接的故障,只实现 ...

  7. 02慕课网《进击Node.js基础(一)》——CommonJs标准

    是一套规范管理模块 每个js 为一个模块,多个模块作为一个包 node.js和Couchdb是对其的实现: 不同于jQuery 模块:定义.标识.引用(地址/模块名称) 模块类型: 核心模块http ...

  8. Spring学习(五)——Spring注解(一)

    ---恢复内容开始--- 概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射 ...

  9. MiniOS系统

    实验一  命令解释程序的编写 一.目的和要求 1. 实验目的 (1)掌握命令解释程序的原理: (2)*掌握简单的DOS调用方法: (3)掌握C语言编程初步. 2.实验要求 编写类似于DOS,UNIX的 ...

  10. JavaScript数组去重的四种方法

    今天,洗澡的想一个有趣的问题,使用js给数组去重,我想了四种方法,虽然今天的任务没有完成,5555: 不多说,po代码: //方法一:简单循环去重    Array.prototype.unique1 ...