题解 UVA1479 【Graph and Queries】
\]
算是一道思维难度稍易,代码难度稍难的题吧。
\]
给出一张 \(n\) 个点,\(m\) 条边的图,点带权。需要支持三个操作:
D x
删掉编号为 \(x\) 的边Q x k
查询与节点 \(x\) 联通的所有节点中,点权第 \(k\) 大节点的点权C x v
将节点 \(x\) 点权改为 \(v\)
多组数据,每组数据最终需要输出所有查询的平均值 ( 保留 6 位 ) ,没有强制在线。
\]
不知道大家有没有做过 这道题 ,推荐先去做一下。
\(~\)
首先,对于同一个连通块里的所有节点,查询与任意一个节点连通的所有节点的第 \(k\) 大,都是查询该连通块里所有节点的第 \(k\) 大。已经很明显可以用并查集维护每个连通块的代表节点,再在这个代表节点上用一个数据结构维护连通块信息,支持合并,查询第 \(k\) 大。
我们发现权值线段树可以做到上述操作,尝试用权值线段树维护,每个节点开一个权值线段树。
\(~\)
对于操作 Q x k
\(:\)
权值线段树基本操作。
对于操作 C x v
\(:\)
我们可以看作是在 \(x\) 这个位置上少了一个原来的点权,再多了一个新的点权,两次插入操作即可解决。
对于操作 D x
\(:\)
\(......\) ,我们发现删掉一条边,不能有效使得一个连通块分裂成两个连通块,并且维护权值线段树。
\(~\)
注意到此题 没有强制在线 ,意味着,我们可以离线地把所有操作都读进来,然后去反着考虑这些询问。
这样一来,D x
操作就可以变为 \(:\) 加入一条编号为 \(x\) 的边。其余的两个操作不变。
我们发现添加一条边很容易维护 \(:\) 找出 \(u,v\) 所在的连通块 \(p,q\) ,若 \(p=q\) ,则无需操作;否则合并权值线段树 \(p\) 和权值线段树 \(q\) ,然后令 \(fa[q]=p\) 。
综上所述,我们就可以用 权值线段树 \(+\) 并查集 解决本题了。\((\) 当然什么 \(splay\),\(treap\) 启发式合并也行 \()\)
时空复杂度 \(\text{O(n log n)}\) 。
\]
#include<cstdio>
#include<cstring>
#define RI register int
using namespace std;
inline int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
}
const int N=6000100,M=6000100,Q=6000100,MLOGN=50000000;
const int INF=1e6;
int T;
int n,m,q;
int cnt;
long double ans;
int val[N];
struct Edge{
int u;
int v;
bool del;
}e[M];
char opt[Q];
int x[Q],k[Q];
int fa[N];
int get(int x)
{
if(fa[x]==x)return x;
return fa[x]=get(fa[x]);
}
int tot,root[N];
struct SegmentTree{
int lc,rc;
int cnt;
}t[MLOGN];
int New()
{
tot++;
t[tot].lc=t[tot].rc=t[tot].cnt=0;
return tot;
}
void insert(int &p,int l,int r,int delta,int val)
{
if(!p)
p=New();
t[p].cnt+=val;
if(l==r)return;
int mid=(l+r)>>1;
if(delta<=mid)
insert(t[p].lc,l,mid,delta,val);
else
insert(t[p].rc,mid+1,r,delta,val);
}
int merge(int p,int q)
{
if(!p||!q)
return p^q;
t[p].cnt+=t[q].cnt;
t[p].lc=merge(t[p].lc,t[q].lc);
t[p].rc=merge(t[p].rc,t[q].rc);
return p;
}
int ask(int p,int l,int r,int k)
{
if(l==r)
return l;
int mid=(l+r)>>1;
int rcnt=t[t[p].rc].cnt;
if(k<=rcnt)
return ask(t[p].rc,mid+1,r,k);
else
return ask(t[p].lc,l,mid,k-rcnt);
}
void link(int u,int v)
{
u=get(u),v=get(v);
if(u==v)return;
root[u]=merge(root[u],root[v]);
fa[v]=u;
}
void work()
{
tot=cnt=ans=q=0;
memset(root,0,sizeof(root));
for(RI i=1;i<=n;i++)
val[i]=read();
for(RI i=1;i<=m;i++)
e[i].u=read(),e[i].v=read();
char tmp[2];
while(scanf("%s",tmp),tmp[0]!='E')
{
opt[++q]=tmp[0];
switch(tmp[0])
{
case 'D':{
x[q]=read();
e[x[q]].del=true;
break;
}
case 'Q':{
x[q]=read(),k[q]=read();
cnt++;
break;
}
case 'C':{
x[q]=read(),k[q]=val[x[q]],val[x[q]]=read();
break;
}
}
}
for(RI i=1;i<=n;i++)
fa[i]=i,insert(root[i],-INF,INF,val[i],1);
for(RI i=1;i<=m;i++)
{
if(e[i].del)continue;
link(e[i].u,e[i].v);
}
for(RI i=q;i>=1;i--)
switch(opt[i])
{
case 'D':{
e[x[i]].del=false;
link(e[x[i]].u,e[x[i]].v);
break;
}
case 'Q':{
int p=get(x[i]);
int A=ask(root[p],-INF,INF,k[i]);
if(A==-INF||A==INF)
continue;
ans+=(long double)A/cnt;
break;
}
case 'C':{
int p=get(x[i]);
insert(root[p],-INF,INF,val[x[i]],-1);
val[x[i]]=k[i];
insert(root[p],-INF,INF,val[x[i]],1);
break;
}
}
printf("Case %d: %Lf\n",++T,ans);
}
int main()
{
while(n=read(),m=read(),n&&m) work();
return 0;
}
\]
题解 UVA1479 【Graph and Queries】的更多相关文章
- UVA1479 Graph and Queries
思路 恶心人的题目 还是类似永无乡一题的Treap启发式合并思路 但是由于加边变成了删边 所以应该离线后倒序处理 数组要开够 代码 #include <cstdio> #include & ...
- HDU 3726 Graph and Queries 平衡树+前向星+并查集+离线操作+逆向思维 数据结构大综合题
Graph and Queries Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- [la P5031&hdu P3726] Graph and Queries
[la P5031&hdu P3726] Graph and Queries Time Limit: 10000/5000 MS (Java/Others) Memory Limit: ...
- HDU 3726 Graph and Queries (离线处理+splay tree)
Graph and Queries Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- HDU 3726 Graph and Queries treap树
题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring ...
- HDU 3726 Graph and Queries(平衡二叉树)(2010 Asia Tianjin Regional Contest)
Description You are given an undirected graph with N vertexes and M edges. Every vertex in this grap ...
- CF1416D Graph and Queries
本题解用于作者加深算法印象,也欢迎各位的阅读. 题目大意 给你一张无向图,并给你两种操作: \(1~v\) :找到当前点 \(v\) 所在的联通块内权值最大的点,输出该点权值并将其权值改为 \(0\) ...
- UVALive5031 Graph and Queries(Treap)
反向操作,先求出最终状态,再反向操作. 然后就是Treap 的合并,求第K大值. #include<cstdio> #include<iostream> #include< ...
- UVa 1479 (Treap 名次树) Graph and Queries
这题写起来真累.. 名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少. 所以在这道题中用一棵名次树来维护一个 ...
随机推荐
- 小白学 Python 爬虫(36):爬虫框架 Scrapy 入门基础(四) Downloader Middleware
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- JavaScript substring()
JavaScript substring() 方法 参数 描述 start 必需.一个非负的整数,规定要提取的子串的第一个字符在 stringObject 中的位置. stop 可选.一个非负的整数, ...
- 《提升能力,涨薪可待》—Java并发之Synchronized
Synchronized简介 线程安全是并发编程中的至关重要的,造成线程安全问题的主要原因: 临界资源, 存在共享数据 多线程共同操作共享数据 而Java关键字synchronized,为多线程场景下 ...
- [JavaScript设计模式] 什么是单例模式
概念 保证一个类仅有一个实例,并提供一个全局访问点 为什么要用单例模式 想象一下某些web应用,当点击登录按钮时,会弹出一个登录框,无论你点击多少次这个登录按钮,登录框都只会出现一个,不会出现多个登录 ...
- 深入理解 CSS(Cascading Style Sheets)中的层叠(Cascading)
标题中的 Cascading 亦可以理解为级联. 进入正文,这是一个很有意思的现象.可以直接跳到 总结一下 部分,看完再回过头来阅读本文. 引子 假设我们有如下结构: <p class=&quo ...
- ubuntu系统搭建(jdk1.8+mysql5.7.28+Hadoop2.7.7+hive3.1.2)
一不小心电脑没电关机之后虚拟机就挂了,然后下定决心重新搭一个虚拟机. 以下是几天安装过程的记录以及一些小提示,包括在ubuntu中安装jdk1.8+mysql5.7.28+Hadoop2.7.7+hi ...
- @Controller和@RestController
@RestController=@Controller+@ResponseBody 1.使用RestController时,返回到前端的内容是Return里的内容,无法返回jsp/html等页面, 此 ...
- 如何编写Robot Framework测试用例1---(基本格式篇)
引子 我们使用符合Robot Framework规范的一种表格语法来编写测试用例.用例一般会是下面这个样子 这样的表格存储到一个文件中,就是一组测试用例.RF支持多种格式,如HTML,TSV,纯文本等 ...
- Oracle Autonomous Health Framework (AHF) 解读
AHF介绍 Oracle在2019年10月18日发布自治健康框架Autonomous Health Framework (AHF) 19.3,将ORAchk,EXAchk,TFA三种诊断工具合并入AH ...
- 11.黑窗口、IDEA生成JavaDoc
JavaDoc: 它是一种技术,可以将一些注释信息生成一个帮助文档,就类似于Java的API JavaAPI帮助文档: https://www.oracle.com/cn/java/technolog ...