UVALive - 5031 Graph and Queries (并查集+平衡树/线段树)
给定一个图,支持三种操作:
1.删除一条边
2.查询与x结点相连的第k大的结点
3.修改x结点的权值
解法:离线倒序操作,平衡树or线段树维护连通块中的所有结点信息,加个合并操作就行了。
感觉线段树要好写很多。
平衡树(Treap)版:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=5e5+;
struct E {
int u,v;
} e[N];
int a[N],faz[N],n,m,del[N];
int father(int x) {return ~faz[x]?faz[x]=father(faz[x]):x;} struct Treap {
static const int N=1e6+;
int rnd() {static int seed=time()%0x7fffffff; return seed=seed*48271ll%0x7fffffff;}
int ch[N][],siz[N],val[N],fa[N],tot,rd[N],rt[N];
void init() {tot=ch[][]=ch[][]=siz[]=val[]=rd[]=;}
int newnode(int x) {
int u=++tot;
ch[u][]=ch[u][]=;
siz[u]=,val[u]=x,rd[u]=rnd();
return u;
}
void pu(int u) {siz[u]=siz[ch[u][]]+siz[ch[u][]]+;}
void rot(int& u,int f) {
int v=ch[u][f];
ch[u][f]=ch[v][f^],ch[v][f^]=u;
pu(u),pu(v),u=v;
}
void ins(int& u,int x) {
if(!u) {u=newnode(x); return;}
int f=x>=val[u];
ins(ch[u][f],x);
if(rd[ch[u][f]]>rd[u])rot(u,f);
if(u)pu(u);
}
void del(int& u,int x) {
if(val[u]==x) {
if(!ch[u][])u=ch[u][];
else if(!ch[u][])u=ch[u][];
else {
int f=rd[ch[u][]]>rd[ch[u][]];
rot(u,f),del(ch[u][f^],x);
}
} else del(ch[u][x>=val[u]],x);
if(u)pu(u);
}
int kth(int u,int k) {
if(!u)return ;
int t=siz[ch[u][]]+;
if(k==t)return val[u];
return k<t?kth(ch[u][],k):kth(ch[u][],k-t);
}
void merge(int& u,int& v) {
if(!u)return;
ins(v,val[u]);
merge(ch[u][],v),merge(ch[u][],v);
}
} treap; struct Q {
int f,u,k;
} qr[N];
int nqr; void mg(int x,int y) {
int fx=father(x),fy=father(y);
if(fx==fy)return;
if(treap.siz[treap.rt[fx]]>treap.siz[treap.rt[fy]])swap(fx,fy);
treap.merge(treap.rt[fx],treap.rt[fy]);
faz[fx]=fy;
} int main() {
int kase=;
while(scanf("%d%d",&n,&m)&&n) {
treap.init();
nqr=;
memset(faz,-,sizeof faz);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
for(int i=; i<=m; ++i)scanf("%d%d",&e[i].u,&e[i].v);
char ch;
while(scanf(" %c",&ch)&&ch!='E') {
if(ch=='Q')scanf("%d%d",&qr[nqr].u,&qr[nqr].k),qr[nqr++].f=;
else if(ch=='D')scanf("%d",&qr[nqr].u),qr[nqr++].f=;
else if(ch=='C')scanf("%d%d",&qr[nqr].u,&qr[nqr].k),swap(a[qr[nqr].u],qr[nqr].k),qr[nqr++].f=;
}
for(int i=; i<=n; ++i)treap.rt[i]=treap.newnode(a[i]);
memset(del,,sizeof del);
for(int i=; i<nqr; ++i)if(qr[i].f==)del[qr[i].u]=;
for(int i=; i<=m; ++i)if(!del[i])mg(e[i].u,e[i].v);
reverse(qr,qr+nqr);
double ans=;
int cnt=;
for(int i=; i<nqr; ++i) {
if(qr[i].f==) {
int u=qr[i].u,r=treap.rt[father(u)],k=qr[i].k;
ans+=treap.kth(r,treap.siz[r]-k+),cnt++;
} else if(qr[i].f==)mg(e[qr[i].u].u,e[qr[i].u].v);
else {
int u=qr[i].u,k=qr[i].k;
int fu=father(u);
treap.del(treap.rt[fu],a[u]);
treap.ins(treap.rt[fu],k);
a[u]=k;
}
}
printf("Case %d: %f\n",++kase,ans/cnt);
}
return ;
}
线段树版:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=5e5+;
struct E {
int u,v;
} e[N];
int a[N],faz[N],n,m,del[N];
int father(int x) {return ~faz[x]?faz[x]=father(faz[x]):x;} struct Segtree {
static const int N=4e6+;
int ls[N],rs[N],siz[N],tot,rt[N];
void init() {tot=ls[]=rs[]=siz[]=;}
int newnode() {int u=++tot; ls[u]=rs[u]=siz[u]=; return u;}
void pu(int u) {siz[u]=siz[ls[u]]+siz[rs[u]];}
void add(int& u,int x,int f,int l=-,int r=) {
if(!u)u=newnode();
siz[u]+=f;
if(l==r)return;
int mid=(l+r)>>;
x<=mid?add(ls[u],x,f,l,mid):add(rs[u],x,f,mid+,r);
}
void merge(int& u,int v,int l=-,int r=) {
if(!v)return;
if(!u) {u=v; return;}
if(l==r) {siz[u]+=siz[v]; return;}
int mid=(l+r)>>;
merge(ls[u],ls[v],l,mid);
merge(rs[u],rs[v],mid+,r);
pu(u);
}
int kth(int u,int k,int l=-,int r=) {
if(l==r)return l;
int mid=(l+r)>>;
return k<=siz[ls[u]]?kth(ls[u],k,l,mid):kth(rs[u],k-siz[ls[u]],mid+,r);
}
} segtree; struct Q {
int f,u,k;
} qr[N];
int nqr; void mg(int x,int y) {
int fx=father(x),fy=father(y);
if(fx==fy)return;
segtree.merge(segtree.rt[fy],segtree.rt[fx]);
faz[fx]=fy;
} int main() {
int kase=;
while(scanf("%d%d",&n,&m)&&n) {
segtree.init();
nqr=;
memset(faz,-,sizeof faz);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
for(int i=; i<=m; ++i)scanf("%d%d",&e[i].u,&e[i].v);
char ch;
while(scanf(" %c",&ch)&&ch!='E') {
if(ch=='Q')scanf("%d%d",&qr[nqr].u,&qr[nqr].k),qr[nqr++].f=;
else if(ch=='D')scanf("%d",&qr[nqr].u),qr[nqr++].f=;
else if(ch=='C')scanf("%d%d",&qr[nqr].u,&qr[nqr].k),swap(a[qr[nqr].u],qr[nqr].k),qr[nqr++].f=;
}
for(int i=; i<=n; ++i)segtree.rt[i]=segtree.newnode(),segtree.add(segtree.rt[i],a[i],);
memset(del,,sizeof del);
for(int i=; i<nqr; ++i)if(qr[i].f==)del[qr[i].u]=;
for(int i=; i<=m; ++i)if(!del[i])mg(e[i].u,e[i].v);
reverse(qr,qr+nqr);
double ans=;
int cnt=;
for(int i=; i<nqr; ++i) {
if(qr[i].f==) {
int u=qr[i].u,r=segtree.rt[father(u)],k=qr[i].k;
if(k>&&k<=segtree.siz[r])ans+=segtree.kth(r,segtree.siz[r]-k+);
cnt++;
} else if(qr[i].f==)mg(e[qr[i].u].u,e[qr[i].u].v);
else {
int u=qr[i].u,k=qr[i].k;
int fu=father(u);
segtree.add(segtree.rt[fu],a[u],-);
segtree.add(segtree.rt[fu],k,);
a[u]=k;
}
}
printf("Case %d: %f\n",++kase,ans/cnt);
}
return ;
}
UVALive - 5031 Graph and Queries (并查集+平衡树/线段树)的更多相关文章
- 【BZOJ2054】疯狂的馒头(并查集,线段树)
[BZOJ2054]疯狂的馒头(并查集,线段树) 题面 BZOJ 然而权限题,随便找个离线题库看看题吧. 题解 线段树就是个暴力,如果数据可以构造就能卡掉,然而不能构造,要不然复杂度瓶颈成为了读入了. ...
- uvalive 5031 Graph and Queries 名次树+Treap
题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...
- POJ 1944 Fiber Communications (枚举 + 并查集 OR 线段树)
题意 在一个有N(1 ≤ N ≤ 1,000)个点环形图上有P(1 ≤ P ≤ 10,000)对点需要连接.连接只能连接环上相邻的点.问至少需要连接几条边. 思路 突破点在于最后的结果一定不是一个环! ...
- ACM学习历程—SNNUOJ 1110 传输网络((并查集 && 离线) || (线段树 && 时间戳))(2015陕西省大学生程序设计竞赛D题)
Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的 ...
- 2019牛客第八场多校 E_Explorer 可撤销并查集(栈)+线段树
目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)E_Explorer) 题意: 链接 题目类似:CF366D,Gym101652T 本题给你\(n(100000)\)个点\(m(1000 ...
- UVALive 5031 Graph and Queries (Treap)
删除边的操作不容易实现,那么就先离线然后逆序来做. 逆序就变成了合并,用并存集判断连通,用Treap树来维护一个连通分量里的名次. Treap = Tree + Heap.用一个随机的优先级来平衡搜索 ...
- UVaLive 5031 Graph and Queries (Treap)
题意:初始时给出一个图,每个点有一个权值,三种操作:(1)删除某个边:(2)修改每个点的权值:(3)询问与节点x在一个连通分量中所有点的第K大的权值. 析:首先是要先离线,然后再倒着做,第一个操作就成 ...
- HDU 3974 Assign the task 并查集/图论/线段树
Assign the task Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...
- CodeForces - 505B Mr. Kitayuta's Colorful Graph 二维并查集
Mr. Kitayuta's Colorful Graph Mr. Kitayuta has just bought an undirected graph consisting of n verti ...
随机推荐
- 常用python模块
webbrowser浏览器控制模块 主要知道 导入 webbrowser使用webbrowser.open(url)运行就可以在默认浏览器打开指定url 来自为知笔记(Wiz)
- 8.22 ps课堂练习
真是做得超烂!以前学的快忘光了!
- 每天一个Linux命令(61)killall命令
killall命令用进程的名字来杀死进程. (1)用法: 用法: killall [ -egiqvw ] [ -signal ] [进程名称] 格式:killall -< ...
- Linux基本命令 压缩命令
1.压缩命令 ================================================================================== 命令名称:gzip ...
- 20145240 《Java程序设计》第四周学习总结
20145240 <Java程序设计>第四周学习总结 教材学习内容总结 6.1继承 6.1.1 继承共同行为 定义:继承基本上就是避免多个类间重复定义共同行为. 优点:1.提高了代码的复用 ...
- 淘宝分类常见---部分显示和全部显示的js效果
需求就是,点击“更多按钮”,显示全部的分类详情,再次点击,显示部分分类. 展开: 收起: 结构: <div class="SubBox" id="SubBox&qu ...
- MongoDB快速入门(五)- Where子句
RDBMS Where子句等效于MongoDB 查询文档在一些条件的基础上,可以使用下面的操作 操作 语法 示例 RDBMS等效语句 Equality {<key>:<value&g ...
- iostream与iostream.h的区别
简单来说: .h的是标准C的头文件,没有.h的是标准C++的头文件,两种都是头文件. 造成这两种形式不同的原因,是C++的发展历史决定的,刚才正好有别的人也问这个问题,这里我再回答一下(注意vs200 ...
- RHCE学习笔记 管理1 (第三~五章)
第三章 红帽企业linux 获取帮助 (略) man .pinfo. 第四章 编辑文件 1.输出重定向到文件和程序 >file 定向文件(覆盖) >>file 定向文件(附 ...
- hive学习7(条件函数case)
case函数 语法: CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END 说明:如果a为TRUE,则返回b:如果c为TRUE,则返回d:否则返回e 实例 ...