当前位置: 代码迷 >> 综合 >> bzoj 1483: [HNOI2009]梦幻布丁 线段树合并
  详细解决方案

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

热度:76   发布时间:2023-10-29 13:41:10.0

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

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

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

经过我无限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;
}