1. 程式人生 > >bzoj 1483: [HNOI2009]夢幻布丁 線段樹合併

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; }