模板题。。去网上学了可撤销的并查集。。

/*
给定一个无向图,边的属性为(u,v,l,r),表示<u,v>可以通过的size为[l,r]
求出有多少不同的size可以从1->n
把每条边的范围[l,r]进行区间离散化然后 建立线段树,然后把每条边按范围更新进线段树里
对线段树进行dfs,同时维护一个可撤销的并查集,经过每个线段树结点都用结点里存的边去更新并查集
到了叶子结点,如果发现[1,n]在同一个集合里,说明联通,那么把这个区间的贡献算上
回溯时要对并查集进行撤销
*/
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define maxn 200005
typedef pair<int,int>pii;
struct Edge{int u,v,l,r;}e[maxn];
int n,m,x[maxn],tot,ans; stack<pii>stk;//合并操作栈
int F[maxn],size[maxn];
int find(int x){//这里不能路径压缩
return F[x]==x?x:find(F[x]);
}
void bing(int x,int y){
int f1=find(x),f2=find(y);
if(f1==f2)//压入无效操作
stk.push(make_pair(-,-));
else {//把f2并入f1
if(size[f1]<size[f2])swap(f1,f2);
size[f1]+=size[f2];
F[f2]=f1;
stk.push(make_pair(f1,f2));
}
}
void cancle(){
pii t=stk.top();stk.pop();
if(t.first==- && t.second==-)return;
size[t.first]-=size[t.second];
F[t.second]=t.second;
return;
} #define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
vector<int>seg[maxn<<];
void update(int L,int R,int id,int l,int r,int rt){
if(L<=l && R>=r){seg[rt].push_back(id);return;}
int m=l+r>>;
if(L<=m)update(L,R,id,lson);
if(R>m)update(L,R,id,rson);
}
void query(int l,int r,int rt){
for(int i=;i<seg[rt].size();i++){
int j=seg[rt][i];
bing(e[j].u,e[j].v);
}
if(l==r){
if(find()==find(n))
ans+=x[l+]-x[l];
for(int i=;i<seg[rt].size();i++)cancle();
return;
}
int m=l+r>>;
query(lson);query(rson);
for(int i=;i<seg[rt].size();i++)cancle();
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].l,&e[i].r);
for(int i=;i<=m;i++){
x[++tot]=e[i].l;
x[++tot]=++e[i].r;
}
sort(x+,x++tot);
tot=unique(x+,x++tot)-x-; for(int i=;i<=m;i++){
int posl=lower_bound(x+,x++tot,e[i].l)-x;
int posr=lower_bound(x+,x++tot,e[i].r)-x;posr--;
update(posl,posr,i,,tot,);
} for(int i=;i<=n;i++)F[i]=i;
for(int i=;i<=n;i++)size[i]=;
query(,tot,);
cout<<ans<<'\n';
}

下面是比较简洁的代码

#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define maxn 400005
typedef pair<int,int>pii; int n,m,x[maxn],tot;
long long ans;
int u[maxn],v[maxn],L[maxn],R[maxn],num[maxn]; stack<pii>stk;//合并操作栈
int fa[maxn],sz[maxn];
int find(int x){//这里不能路径压缩
return fa[x]==x?x:find(fa[x]);
}
void bing(int x,int y){
int f1=find(x),f2=find(y);
if(f1==f2)//压入无效操作
stk.push(make_pair(-,-));
else {//把f2并入f1
if(sz[f1]<sz[f2])swap(f1,f2);
sz[f1]+=sz[f2];
fa[f2]=f1;
stk.push(make_pair(f1,f2));
}
}
void cancel(){
pii t=stk.top();stk.pop();
if(t.first==- && t.second==-)return;
sz[t.first]-=sz[t.second];
fa[t.second]=t.second;
} #define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
vector<int>seg[maxn<<];
void update(int L,int R,int id,int l,int r,int rt){
if(L<=l && R>=r){seg[rt].push_back(id);return;}
int m=l+r>>;
if(L<=m)update(L,R,id,lson);
if(R>m)update(L,R,id,rson);
}
void query(int l,int r,int rt){
for(int i=;i<seg[rt].size();i++){
int j=seg[rt][i];
bing(u[j],v[j]);
}
if(l==r){
if(find()==find(n))
ans+=num[l+]-num[l];
for(int i=;i<seg[rt].size();i++)cancel();
return;
}
int m=l+r>>;
query(lson);query(rson);
for(int i=;i<seg[rt].size();i++)cancel();
}
int main(){
cin>>n>>m;
for(int i=;i<=m;i++){
cin>>u[i]>>v[i]>>L[i]>>R[i];
num[++tot]=L[i];
num[++tot]=++R[i];
}
sort(num+,num++tot);
tot=unique(num+,num++tot)-num-; for(int i=;i<=m;i++){
int posl=lower_bound(num+,num++tot,L[i])-num;
int posr=lower_bound(num+,num++tot,R[i])-num-;
update(posl,posr,i,,tot-,);
}
for(int i=;i<=n;i++)fa[i]=i,sz[i]=;
query(,tot-,);
cout<<ans<<endl;
}

线段树区间离散化维护按秩合并并查集(可撤销)——牛客多校第八场E的更多相关文章

  1. 2019牛客多校第八场 F题 Flowers 计算几何+线段树

    2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...

  2. 牛客多校第八场E Explorer(左开右闭线段树+可撤回并查集)题解

    题意: 传送门 有\(n\)个点构成一个无向图,每条边有\(L_i,R_i\)表示这条边只能允许编号为\(L_i\dots R_i\)的人通过,现在问你最多有几个人能从\(1\)走到\(n\). 思路 ...

  3. Explorer(2019年牛客多校第八场E题+线段树+可撤销并查集)

    题目链接 传送门 题意 给你一张无向图,每条边\(u_i,v_i\)的权值范围为\([L_i,R_i]\),要经过这条边的条件是你的容量要在\([L_i,R_i]\),现在问你你有多少种容量使得你可以 ...

  4. Distance(2019年牛客多校第八场D题+CDQ+树状数组)

    题目链接 传送门 思路 这个题在\(BZOJ\)上有个二维平面的版本(\(BZOJ2716\)天使玩偶),不过是权限题因此就不附带链接了,我也只是在算法进阶指南上看到过,那个题的写法是\(CDQ\), ...

  5. 暴力三维树状数组求曼哈顿距离求最值——牛客多校第八场D

    涉及的知识点挺多,但是大多是套路 1.求曼哈顿距离的最值一般对所有情况进行讨论 2.三维树状数组用来求前缀最大值 /* 有一个三维坐标系(x,y,z),取值范围为[1,n],[1,m],[1,h],有 ...

  6. Codeforces 1140F Extending Set of Points 线段树 + 按秩合并并查集 (看题解)

    Extending Set of Points 我们能发现, 如果把x轴y轴看成点, 那么答案就是在各个连通块里面的x轴的个数乘以y轴的个数之和. 然后就变成了一个并查集的问题, 但是这个题目里面有撤 ...

  7. 牛客多校第三场 G Removing Stones(分治+线段树)

    牛客多校第三场 G Removing Stones(分治+线段树) 题意: 给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半 题解: 分治+线段树 线段树维护最 ...

  8. 牛客多校第四场sequence C (线段树+单调栈)

    牛客多校第四场sequence C (线段树+单调栈) 传送门:https://ac.nowcoder.com/acm/contest/884/C 题意: 求一个$\max {1 \leq l \le ...

  9. BZOJ 4668 冷战(按秩合并并查集+LCA)

    4668: 冷战 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 627  Solved: 303[Submit][Status][Discuss] D ...

随机推荐

  1. web.xml中配置——配置springmvc

    <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springfr ...

  2. Python删除文件夹

    import os os.rmdir('OS-Demo-2') os.removedirs('OS-Demo-3/sub-Dir-1') os.removedirs()会自动将上一级文件夹也删除,谨慎 ...

  3. Faster-RCNN论文精读

    State-of-the-art object detection networks depend on region proposal algorithms to hypothesize objec ...

  4. 分布式项目web.xml配置文件的表头

    <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://w ...

  5. go指定分隔符格式化时间

    一.代码 package main import ( "fmt" "strings" "strconv" "time" ...

  6. 使用PHP curl模拟浏览器抓取网站信息

    curl是一个利用URL语法在命令行方式下工作的文件传输工具.curl是一个利用URL语法在命令行方式下工作的文件传输工具.它支持很多协议:FTP, FTPS, HTTP, HTTPS, GOPHER ...

  7. jmeter 创建接口测试案例

    1 怎么做接口测试? 一般情况下,由于我们项目前后调用主要是基于http协议的接口,所以测试接口时主要是通过工具或代码模拟http请求的发送和接收.所以我们下面整理了一下使用Jmeter工具进行htt ...

  8. python url编码与解码

    上代码 #codeing:utf-8 from urllib import parse ori_url_10='http://192.168.0.10:3080/asg/portal.do?call= ...

  9. 2019牛客多校第三场B-Crazy Binary String(前缀和+思维)

    Crazy Binary String 题目传送门 解题思路 把1记为1,把0记为-1,然后求前缀和,前缀和相等的就说明中间的01数一样.只要记录前缀和数值出现的位置即可更新出答案. 代码如下 #in ...

  10. upc组队赛2 Master of GCD 【线段树区间更新 || 差分】

    Master of GCD 题目描述 Hakase has n numbers in a line. At fi rst, they are all equal to 1. Besides, Haka ...