感觉做得有点复杂了,但是AC了还是。。。爽。。。

题意:给你n个点每个点有一个价值,接下来有m条边,然后是q个操作,每个操作有三种情况:

F X K:寻找与X点直接或间接相连的不小于价值K的最小价值,如果找不到就是0

U X K:将X点价值变为K

E A B:删除点A与点B形成的边

最后求价值总和的平均值

首先我们看F操作和U操作可以使用map解决,因为这是典型的带修改并区间找寻大于等于某值的最小值。然后我们看删边,如果直接删的话,我们需要遍历这一维map然后拆分,时间过不了。因此我们想到使用离线操作倒序添边,然后处理集合合并问题就是并查集的典型题了。

接着我们离线后要把每个E与U都处理后再添边,对于U我们必须保存所有修改的历史,因此使用vector。而m条边中删除E的边,我们需要节约时间。存下总所有边与需要删除的边,然后一起排序后双指针维护添边(因为需要删除的边一定在所有边中出现过,且没有重边)。接着对于维护E,添边后需要把一个父节点并上去,且两个map也要合并,因此我们为了节约合并时间,需要简单的启发式合并。其实就是并查集合并时把个数少的并到个数多的上面。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=<<;
const double Pi=acos(-1.0);
const int Mod=1e9+;
const int Max=;
struct node
{
char typ[];
int u,v;
}add[Max],del[Max],ope[Max];
int fat[Max],ran[Max];//离线添边的并查集
map<int,int> mp[Max];//祖先形成的集合里的元素
vector<int> vec[Max];//存下修改的过程值
int len[Max];
void Init(int n)
{
for(int i=;i<n;++i)
{
ran[i]=;
len[i]=;
vec[i].clear();
mp[i].clear();
fat[i]=i;
}
return;
}
int Find(int x)
{
if(x==fat[x])
return fat[x];
return fat[x]=Find(fat[x]);
}
void UnMap(int x1,int y1)
{
for(map<int,int>::iterator it=mp[x1].begin();it!=mp[x1].end();)
{
if(!mp[y1].count(it->first))
mp[y1][it->first]=it->second;
else
mp[y1][it->first]+=it->second;
mp[x1].erase(it++);//删除
}
return;
}
void Union(int x,int y)
{
int x1=Find(x);
int y1=Find(y);
if(x1==y1)
return;
if(ran[x1]<ran[y1])
{
fat[x1]=y1;//价值合并
ran[y1]+=ran[x1];
UnMap(x1,y1);
}
else
{
fat[y1]=x1;//价值合并
ran[x1]+=ran[y1];
UnMap(y1,x1);
}
return;
}
bool cmp(struct node p1,struct node p2)
{
if(p1.u==p2.u)
return p1.v<p2.v;
return p1.u<p2.u;
}
map<int,int>::iterator it;
double Solve(int n,int m,int q,int cnt,int dig)
{
int coun=;
double ans=0.0;
for(int i=;i<n;++i)
mp[i][vec[i][len[i]]]=;//开始每个集合是自己
sort(add,add+m,cmp);
sort(del,del+cnt,cmp);
del[cnt].u=del[cnt].v=-;
//for(int i=0;i<m;++i)
// printf("%d %d\n",add[i].u,add[i].v);
// printf("OK\n");
// for(int i=0;i<cnt;++i)
//printf("%d %d\n",del[i].u,del[i].v);
for(int i=;i<m;++i)//初始添边
{
if(add[i].u==del[coun].u&&add[i].v==del[coun].v)//两边排序后双指针维护
coun++;
else
{//printf("OK\n");
Union(add[i].u,add[i].v);
}
}
for(int i=q-;i>=;--i)
{
if(ope[i].typ[]=='F')
{
int x1=Find(ope[i].u);
it=mp[x1].lower_bound(ope[i].v);
if(it==mp[x1].end())
ans+=0.0;
else
ans+=it->first;
}
else if(ope[i].typ[]=='E')
Union(ope[i].u,ope[i].v);
else//换价值
{
int x1=Find(ope[i].u);
mp[x1][ope[i].v]--;
if(mp[x1][ope[i].v]==)
mp[x1].erase(ope[i].v);
if(mp[x1].count(vec[ope[i].u][len[ope[i].u]-]))
mp[x1][vec[ope[i].u][--len[ope[i].u]]]++;
else
mp[x1][vec[ope[i].u][--len[ope[i].u]]]=;
}
}//printf("%d\n",dig);
return ans/dig;
}
int main()
{
int n,m,q;
int u,v,c;
int cnt,dig,coun=;
while(~scanf("%d %d %d",&n,&m,&q))
{
Init(n);
dig=cnt=;
for(int i=;i<n;++i)
{
scanf("%d",&c);
vec[i].push_back(c);
}
for(int i=;i<m;++i)
{
scanf("%d %d",&u,&v);
u--,v--;
if(u>v)
swap(u,v);
add[i].u=u;
add[i].v=v;
}
for(int i=;i<q;++i)
{
scanf("%s %d %d",&ope[i].typ,&ope[i].u,&ope[i].v);
if(ope[i].typ[]=='F')
{
dig++;
ope[i].u--;
}
else if(ope[i].typ[]=='E')
{
ope[i].u--,ope[i].v--;
if(ope[i].u>ope[i].v)
swap(ope[i].u,ope[i].v);
del[cnt].u=ope[i].u,del[cnt++].v=ope[i].v;
}
else
{
ope[i].u--;
len[ope[i].u]++;
vec[ope[i].u].push_back(ope[i].v);
}
}
printf("Case %d: %.3f\n",++coun,Solve(n,m,q,cnt,dig));
Init(n);
}
return ;
}

HDU 2419 Boring Game(并查集+map)的更多相关文章

  1. HDU 1811 拓扑排序 并查集

    有n个成绩,给出m个分数间的相对大小关系,问是否合法,矛盾,不完全,其中即矛盾即不完全输出矛盾的. 相对大小的关系可以看成是一个指向的条件,如此一来很容易想到拓扑模型进行拓扑排序,每次检查当前入度为0 ...

  2. hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点)

    hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点) 题意: 给一张无向连通图,有两种操作 1 u v 加一条边(u,v) 2 u v 计算u到v路径上桥的个数 ...

  3. HDU(3560)成环,并查集

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3560 并查集查有几个块,修改了之前我的一个方法(用什么map),直接判断根节点的id是i的个数. 然后 ...

  4. HDU 2473 Junk-Mail Filter 并查集,虚拟删除操作

    http://acm.hdu.edu.cn/showproblem.php?pid=2473 给定两种操作 第一种是合并X Y 第二种是把X分离出来,就是从原来的集合中分离出来,其它的关系不变. 关键 ...

  5. HDU 2473 Junk-Mail Filter(并查集的删除操作)

    题目地址:pid=2473">HDU 2473 这题曾经碰到过,没做出来. .如今又做了做,还是没做出来. ... 这题涉及到并查集的删除操作.想到了设一个虚节点,可是我把虚节点设为了 ...

  6. HDU 5441 离线处理 + 并查集

    题意:给n个节点m条带权值边的无向图.然后q个问题,每次询问点对的数目,点对需要满足的条件是:1)连通:2)其路径的最大权值不能超过询问值. 分析:如果没次询问一次,dfs一次,很可能超时,因此可以用 ...

  7. HDU 4496 D-City (并查集)

    题意:有n个城市,m条路,首先m条路都连上,接着输出m行,第i行代表删除前i行的得到的连通块个数 题解:正难则反,我们反向考虑使用并查集添边.首先每个点都没有相连,接着倒着来边添加边计算,当两个点父节 ...

  8. HDU 5441 Travel (并查集+数学+计数)

    题意:给你一个带权的无向图,然后q(q≤5000)次询问,问有多少对城市(城市对(u,v)与(v,u)算不同的城市对,而且u≠v)之间的边的长度不超过d(如果城市u到城市v途经城市w, 那么需要城市u ...

  9. hdu 2480 贪心+简单并查集

    Steal the Treasure Time Limit: 10000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

随机推荐

  1. Java 基础巩固:IO

    在学习IO的时候发现IO的类太多,如InputStream下面就用ReaderInputStream.InputStreamBuffer等等, 还用Reader.Writer.OutputStream ...

  2. 边双联通问题求解(构造边双连通图)POJ3352(Road Construction)

    题目链接:传送门 题目大意:给你一副无向图,问至少加多少条边使图成为边双联通图 题目思路:tarjan算法加缩点,缩点后求出度数为1的叶子节点个数,需要加边数为(leaf+1)/2 #include ...

  3. Cocos2d-x Lua中使用标签

    游戏场景中的文字包括了静态文字和动态文字.静态文字如下图所示游戏场景中①号文字“COCOS2DX”,动态文字如图4-1所示游戏场景中的②号文字“Hello World”.静态文字一般是由美工使用Pho ...

  4. Centos7配置外部网络访问

    Centos7配置外部网络访问 一.安装步骤中的重要配置: 默认是动态ip配置,有需要可以改成静配置 BOOTPROTO="static" 二.如果不能联网,按照如下步骤设置网络: ...

  5. 巨蟒django之权限7:动态生成一级&&二级菜单

    内容回顾: . 权限的控制 . 表结构设计 存权限的信息 用户表 - name 用户名 - pwd 密码 - roles 多对多 角色表 - name - permissions 多对多 权限表 - ...

  6. 让vs只启动自己想调试的站点

    VS中里面多个WEB项目如何只启动一个? 每次启动时,右下角都会出现一堆的 网站有10来个.即使设置了默认启动项目, 但每次按F5启动,或者哪怕是在项目上右键启动新实例 右下角都会出现这一堆的站点 有 ...

  7. JavaWeb 之邮件发送

    1. 邮件协议概述 SMTP(Simple Mail Transfer Protocol, 简单邮件传输协议) 发邮件协议; POP3(Post Office Protocol Version 3, ...

  8. 算法题 19 二叉平衡树检查 牛客网 CC150

    算法题 19 二叉平衡树检查 牛客网 CC150 实现一个函数,检查二叉树是否平衡,平衡的定义如下,对于树中的任意一个结点,其两颗子树的高度差不超过1. 给定指向树根结点的指针TreeNode* ro ...

  9. 剑指offer 面试13题

    面试13题: 题目:机器人的运动范围 题:地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子 ...

  10. Loadrunder之脚本篇——参数化同行取值

    select next row 记录选择方式 Same line as,这个选项只有当参数多余一个时才会出现,其作用是根据某一个参数的行号取同一行. 例中的做法如下: 将多个参数存放在一个参数文件中: ...