bzoj 1483: [HNOI2009]梦幻布丁 线段树合并

题意很简单,但是没有数据范围,这就是这题最难的地方

考虑线段树合并。。
就是随便搞搞
相信大家都会。。

就是这个数据范围很坑爹。。。

经过我无限WA和RE
我得出了以下结论:
1.数字可以很大
2.n不超过10W
3.询问非常非常多,比10W不知道高到哪里去了

通过结论1和2,我们知道可以用离散化
然后由由于性质3,上面一句作废,因为我开了100W的数组都没装下这个东西。。也可能是我的姿势不对

或许有的读者会说,那我可以只对一开始的离散化啊!!!
那么你后面怎么办,会有问题的,我打过了。。

那么我们考虑使用map,于是就A了

这个辣鸡数据范围,害我搞了这么久

#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100005;
int n,m;
struct qq
{
    int c,s1,s2; 
    bool L,R;
}s[N*20];int num=0;
map<int,int> root;
void change (int &now,int l,int r,int x)
{
    if (now==0) now=++num;
    if (l==r) {s[now].L=s[now].R=true;s[now].c=1;return ;}
    int mid=(l+r)>>1;
    if (x<=mid) change(s[now].s1,l,mid,x);
    else change(s[now].s2,mid+1,r,x);
    s[now].c=s[s[now].s1].c+s[s[now].s2].c;
    s[now].L=s[s[now].s1].L;s[now].R=s[s[now].s2].R;
    if (s[s[now].s1].R&&s[s[now].s2].L) s[now].c--;
}
int ans=0;
void Merge (int &x,int &y)//吧x的全部东西送给y 
{
    if (x==0) return ;
    if (y==0) {y=x;x=0;return ;}
    Merge(s[x].s1,s[y].s1);
    Merge(s[x].s2,s[y].s2);
    s[y].c=s[s[y].s1].c+s[s[y].s2].c;
    s[y].L=s[s[y].s1].L;s[y].R=s[s[y].s2].R;
    if (s[s[y].s1].R&&s[s[y].s2].L) s[y].c--;
    x=0;
}
int shen[N],cnt;
int main()
{
    s[0].c=0;
    s[0].L=s[0].R=false;
    scanf("%d%d",&n,&m);
    for (int u=1;u<=n;u++)
    {
        int x;
        scanf("%d",&x);
        shen[u]=x;
        change(root[x],1,n,u);
    }

    sort(shen+1,shen+1+n);
    cnt=1;ans=s[root[shen[1]]].c;
    for (int u=2;u<=n;u++)
        if (shen[u]!=shen[cnt])
        {
            shen[++cnt]=shen[u];
            ans=ans+s[root[shen[u]]].c;
        }

    for (int u=1;u<=m;u++)
    {
        int x;
        scanf("%d",&x);
        if (x==2) printf("%d\n",ans);
        else
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if (a==b) continue;
            ans=ans-s[root[a]].c-s[root[b]].c;
            Merge(root[a],root[b]);
            ans=ans+s[root[b]].c;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值