HDU 2419 Boring Game(并查集+map)
感觉做得有点复杂了,但是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)的更多相关文章
- HDU 1811 拓扑排序 并查集
有n个成绩,给出m个分数间的相对大小关系,问是否合法,矛盾,不完全,其中即矛盾即不完全输出矛盾的. 相对大小的关系可以看成是一个指向的条件,如此一来很容易想到拓扑模型进行拓扑排序,每次检查当前入度为0 ...
- hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点)
hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点) 题意: 给一张无向连通图,有两种操作 1 u v 加一条边(u,v) 2 u v 计算u到v路径上桥的个数 ...
- HDU(3560)成环,并查集
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3560 并查集查有几个块,修改了之前我的一个方法(用什么map),直接判断根节点的id是i的个数. 然后 ...
- HDU 2473 Junk-Mail Filter 并查集,虚拟删除操作
http://acm.hdu.edu.cn/showproblem.php?pid=2473 给定两种操作 第一种是合并X Y 第二种是把X分离出来,就是从原来的集合中分离出来,其它的关系不变. 关键 ...
- HDU 2473 Junk-Mail Filter(并查集的删除操作)
题目地址:pid=2473">HDU 2473 这题曾经碰到过,没做出来. .如今又做了做,还是没做出来. ... 这题涉及到并查集的删除操作.想到了设一个虚节点,可是我把虚节点设为了 ...
- HDU 5441 离线处理 + 并查集
题意:给n个节点m条带权值边的无向图.然后q个问题,每次询问点对的数目,点对需要满足的条件是:1)连通:2)其路径的最大权值不能超过询问值. 分析:如果没次询问一次,dfs一次,很可能超时,因此可以用 ...
- HDU 4496 D-City (并查集)
题意:有n个城市,m条路,首先m条路都连上,接着输出m行,第i行代表删除前i行的得到的连通块个数 题解:正难则反,我们反向考虑使用并查集添边.首先每个点都没有相连,接着倒着来边添加边计算,当两个点父节 ...
- HDU 5441 Travel (并查集+数学+计数)
题意:给你一个带权的无向图,然后q(q≤5000)次询问,问有多少对城市(城市对(u,v)与(v,u)算不同的城市对,而且u≠v)之间的边的长度不超过d(如果城市u到城市v途经城市w, 那么需要城市u ...
- hdu 2480 贪心+简单并查集
Steal the Treasure Time Limit: 10000/6000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
随机推荐
- jpofiler监控JVM
1.官方下载地址,选择自己想要的版本 https://www.ej-technologies.com/download/jprofiler/version_92 2.分为linux服务端.window ...
- 160824、ionic添加地图站点
1.基本的地图显示 <!DOCTYPE html> <html ng-app="myApp"> <head> <meta charset= ...
- python系列二:python3基本数据类型
#标准数据类型——number(数字)a, b, c = 1, 2.2, "hello"print(a, end = ", ")print(b, end = & ...
- DIV背景图片
.bigY{ position:absolute; width:95px; height:93px; visibility:visible; right: 277 ...
- Python 是怎么火起来的?
Python 之父 Guido 正在设计 Python 语言,结果家里突然潜入一条大蟒蛇,一番激烈斗争,大蟒蛇把 Guido 叔生吞进肚,并洋洋自得:So Who is Guido Van Rossu ...
- 使用Kotlin开发Android应用 - 环境搭建 (1)
一. 在Android Studio上安装Kotlin插件 按快捷键Command+, -> 在Preferences界面找到Plugins -> 点击Browse repositorie ...
- 剑指offer 面试47题
面试47题:题:礼物的最大价值 题目:在一个mxn的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0),你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格,直到到达棋盘的 ...
- 【转】ModelAndView 学习
http://blog.csdn.net/wavaya/article/details/6185226 ModelAndView 类别就如其名称所示,是代表了Spring Web MVC程式中呈现画面 ...
- 使用BUCK进行iOS项目打包
关于BUCK BUCK是Facebook开源的快速打包工具,可以用于多种语言及平台的项目打包,例如:C.C++.Java.iOS.Android等等.用于大型的iOS.Android项目,可以显著提升 ...
- linux切换用户命令
1. 切换用户的命令为:su +username 2.从普通用户切换到root用户:sudo su 3.退回到原来的用户:exit命令或logout,或者ctrl+d 4.如果要切换到新用户的工作环境 ...