bzoj2333: [SCOI2011]棘手的操作(启发式合并做法)

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=2333

题解

  网上的题解怎么都是可并堆啊,好厉害的样子,我不会…
  这题可以启发式合并,每个并查集的根节点维护一个堆,然后启发式合并搞搞就好啦。
  其中维护堆的部分我们可以搞一个修改标记表示这个堆里的所有元素都被加了几,没啥好说的了吧..
  时间复杂度 O(Nlog2N)

代码

//启发式合并+堆+并查集 
#include <cstdio>
#include <algorithm>
#include <queue>
#define heap priority_queue
#define maxn 300005
using namespace std;
int N, Q, f[maxn], V, d[maxn], a[maxn], vis[maxn];
struct data{int id, w;data(int a, int b):id(a),w(b){}data(){}}stack[maxn];
heap<data> h[maxn], big;
bool operator<(const data &a, const data &b){return a.w<b.w;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline void upd(int x)
{
    if(x)while(a[h[x].top().id]^h[x].top().w)h[x].pop();
    else while(h[big.top().id].empty() or
                h[big.top().id].top().w+d[big.top().id]!=big.top().w)big.pop();
}
inline void merge(int x, int y)
{
    int fx=find(x), fy=find(y);
    if(fx==fy)return;
    if(h[fx].size()>h[fy].size())swap(fx,fy);
    for(;!h[fx].empty();h[fx].pop())
        if(h[fx].top().w==a[h[fx].top().id] and vis[h[fx].top().id]!=Q)
            h[fy].push(data(h[fx].top().id,h[fx].top().w+d[fx]-d[fy])),
            a[h[fx].top().id]+=d[fx]-d[fy], vis[h[fx].top().id]=Q;
    f[fx]=fy;
    upd(fy);
    big.push(data(fy,h[fy].top().w+d[fy]));
    upd(0);
}
inline int read(int x=0)
{
    char c=getchar(); bool f=0;
    while(c<48 or c>57)f=f or c=='-', c=getchar();
    while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48, c=getchar();
    return f?-x:x;
}
int main()
{
    char type[5]; int x, v, i, fx;
    scanf("%d",&N);
    for(i=1;i<=N;i++)
        scanf("%d",a+i), f[i]=i, h[i].push(data(i,a[i])), big.push(data(i,a[i]));
    scanf("%d",&Q);
    for(Q++;Q^1;Q--)
    {
        scanf("%s",type);
        if(*type=='U')x=read(), v=read(), merge(x,v);
        if(*type=='A')
        {
            if(type[1]=='1')
            {
                x=read(), v=read();
                a[x]+=v;
                h[fx=find(x)].push(data(x,a[x]));
                upd(fx);
                big.push(data(fx,h[fx].top().w+d[fx]));
                upd(0);
            }
            if(type[1]=='2')
            {
                x=read(), v=read();
                d[fx=find(x)]+=v;
                big.push(data(fx,h[fx].top().w+d[fx]));
                upd(0);
            }
            if(type[1]=='3')d[0]+=read();
        }
        if(*type=='F')
        {
            if(type[1]=='1')
                x=read(), printf("%d\n",a[x]+d[find(x)]+d[0]);
            if(type[1]=='2')
                x=read(), printf("%d\n",h[find(x)].top().w+d[find(x)]+d[0]);
            if(type[1]=='3')
                printf("%d\n",big.top().w+d[0]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值