bzoj 1483: [HNOI2009]夢幻布丁 線段樹合併
阿新 • • 發佈:2019-02-11
題意很簡單,但是沒有資料範圍,這就是這題最難的地方
考慮線段樹合併。。
就是隨便搞搞
相信大家都會。。
就是這個資料範圍很坑爹。。。
經過我無限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;
}