UVALive - 5031 Graph and Queries (并查集+平衡树/线段树)

时间:2023-02-06 16:52:07

给定一个图,支持三种操作:

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 (并查集+平衡树/线段树)的更多相关文章

  1. 【BZOJ2054】疯狂的馒头(并查集,线段树)

    [BZOJ2054]疯狂的馒头(并查集,线段树) 题面 BZOJ 然而权限题,随便找个离线题库看看题吧. 题解 线段树就是个暴力,如果数据可以构造就能卡掉,然而不能构造,要不然复杂度瓶颈成为了读入了. ...

  2. uvalive 5031 Graph and Queries 名次树&plus;Treap

    题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...

  3. POJ 1944 Fiber Communications &lpar;枚举 &plus; 并查集 OR 线段树&rpar;

    题意 在一个有N(1 ≤ N ≤ 1,000)个点环形图上有P(1 ≤ P ≤ 10,000)对点需要连接.连接只能连接环上相邻的点.问至少需要连接几条边. 思路 突破点在于最后的结果一定不是一个环! ...

  4. ACM学习历程—SNNUOJ 1110 传输网络(&lpar;并查集 &amp&semi;&amp&semi; 离线&rpar; &vert;&vert; &lpar;线段树 &amp&semi;&amp&semi; 时间戳&rpar;)(2015陕西省大学生程序设计竞赛D题)

    Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的 ...

  5. 2019牛客第八场多校 E&lowbar;Explorer 可撤销并查集&lpar;栈&rpar;&plus;线段树

    目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)E_Explorer) 题意: 链接 题目类似:CF366D,Gym101652T 本题给你\(n(100000)\)个点\(m(1000 ...

  6. UVALive 5031 Graph and Queries (Treap)

    删除边的操作不容易实现,那么就先离线然后逆序来做. 逆序就变成了合并,用并存集判断连通,用Treap树来维护一个连通分量里的名次. Treap = Tree + Heap.用一个随机的优先级来平衡搜索 ...

  7. UVaLive 5031 Graph and Queries &lpar;Treap&rpar;

    题意:初始时给出一个图,每个点有一个权值,三种操作:(1)删除某个边:(2)修改每个点的权值:(3)询问与节点x在一个连通分量中所有点的第K大的权值. 析:首先是要先离线,然后再倒着做,第一个操作就成 ...

  8. HDU 3974 Assign the task 并查集&sol;图论&sol;线段树

    Assign the task Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...

  9. CodeForces - 505B Mr&period; Kitayuta&&num;39&semi;s Colorful Graph 二维并查集

    Mr. Kitayuta's Colorful Graph Mr. Kitayuta has just bought an undirected graph consisting of n verti ...

随机推荐

  1. 【转】Android中处理崩溃异常

    大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了 ...

  2. Borg Maze 分类: POJ 2015-07-27 15&colon;28 5人阅读 评论&lpar;0&rpar; 收藏

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9971   Accepted: 3347 Description The B ...

  3. Asp&period;net MVC4高级编程学习笔记-视图学习第一课20171009

    首先解释下:本文只是对Asp.net MVC4高级编程这本书学习记录的学习笔记,书本内容感觉挺简单的,但学习容易忘记,因此在边看的同时边作下了笔记,可能其它朋友看的话没有情境和逻辑顺序还请谅解! 一. ...

  4. 我的web聊天之---序章

    有时候自我感觉良好,人啊就开始膨胀,细细想来,自己还是那么苍白.---- 致傻傻的我 大家都知道,平时上班总是拿着手机看看微信,看看新闻,这个不太好,这不是重点,重点是我们公司web版本的微信,QQ都 ...

  5. &lbrack;Swift&rsqb;LeetCode605&period; 种花问题 &vert; Can Place Flowers

    Suppose you have a long flowerbed in which some of the plots are planted and some are not. However, ...

  6. Leetcode&colon; The Maze II

    There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolli ...

  7. Oracle提取中文字符串拼音首字母函数

    通过oracle的NLSSORT函数对汉字按照拼音排序,然后根据汉字的区间返回对应的首字母. 效果1,获取拼音简码: 效果2,获取姓名首字母: 创建函数: /* 获取拼音简码函数 */ CREATE ...

  8. 在windows上安装VTK

    看了很多教程,花了1天半的时间装上了,记录下. 前置条件:我安装了VS2015,用来编译工程. 参考资料 官方:http://www.vtk.org/Wiki/VTK/Building 安装:http ...

  9. QML事件处理 八

    1.MouseArea MouseArea 是一个不可见的项目,通常用来和一个可见的项目配合使用来为其提供鼠标处理.鼠标处理的逻辑可以包含在一个MouseArea项目中. MouseArea的enab ...

  10. 【MVC】ASP&period;NET MVC5 使用MiniProfiler 监控MVC性能

    MiniProfiler ,一个简单而有效的迷你剖析器,可以有效的实时监控页面.通过直接引用.Ajax.Iframe形式访问的其它页面进行监控,监控内容包括数据库内容,并可以显示数据库访问的SQL. ...