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=1<<28;
const double Pi=acos(-1.0);
const int Mod=1e9+7;
const int Max=300010;
struct node
{
    char typ[2];
    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=0;i<n;++i)
    {
        ran[i]=1;
        len[i]=0;
        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=0;
    double ans=0.0;
    for(int i=0;i<n;++i)
        mp[i][vec[i][len[i]]]=1;//开始每个集合是自己
        sort(add,add+m,cmp);
        sort(del,del+cnt,cmp);
        del[cnt].u=del[cnt].v=-1;
        //for(int i=0;i<m;++i)
        //    printf("%d %d
",add[i].u,add[i].v);
         //   printf("OK
");
       // for(int i=0;i<cnt;++i)
            //printf("%d %d
",del[i].u,del[i].v);
    for(int i=0;i<m;++i)//初始添边
    {
        if(add[i].u==del[coun].u&&add[i].v==del[coun].v)//两边排序后双指针维护
            coun++;
    else
    {//printf("OK
");
         Union(add[i].u,add[i].v);
    }
    }
    for(int i=q-1;i>=0;--i)
    {
        if(ope[i].typ[0]=='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[0]=='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]==0)
                mp[x1].erase(ope[i].v);
                if(mp[x1].count(vec[ope[i].u][len[ope[i].u]-1]))
            mp[x1][vec[ope[i].u][--len[ope[i].u]]]++;
            else
                 mp[x1][vec[ope[i].u][--len[ope[i].u]]]=1;
        }
    }//printf("%d
",dig);
    return ans/dig;
}
int main()
{
    int n,m,q;
    int u,v,c;
    int cnt,dig,coun=0;
    while(~scanf("%d %d %d",&n,&m,&q))
    {
        Init(n);
        dig=cnt=0;
        for(int i=0;i<n;++i)
        {
            scanf("%d",&c);
            vec[i].push_back(c);
        }
        for(int i=0;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=0;i<q;++i)
        {
            scanf("%s %d %d",&ope[i].typ,&ope[i].u,&ope[i].v);
            if(ope[i].typ[0]=='F')
            {
                dig++;
            ope[i].u--;
            }
            else if(ope[i].typ[0]=='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
",++coun,Solve(n,m,q,cnt,dig));
        Init(n);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/5894750.html