日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

曼哈顿距离最小生成树与莫队算法(总结)

發布時間:2025/3/15 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 曼哈顿距离最小生成树与莫队算法(总结) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

曼哈頓距離最小生成樹與莫隊算法(總結)

1 曼哈頓距離最小生成樹

曼哈頓距離最小生成樹問題可以簡述如下:?
給定二維平面上的N個點,在兩點之間連邊的代價為其曼哈頓距離,求使所有點連通的最小代價。?
樸素的算法可以用O(N2)的Prim,或者處理出所有邊做Kruskal,但在這里總邊數有O(N2)條,所以Kruskal的復雜度變成了O(N2logN)。?
但是事實上,真正有用的邊遠沒有O(N2)條。我們考慮每個點會和其他一些什么樣的點連邊。可以得出這樣一個結論,以一個點為原點建立直角坐標系,在每45度內只會向距離該點最近的一個點連邊。?
這個結論可以證明如下:假設我們以點A為原點建系,考慮在y軸向右45度區域內的任意兩點B(x1,y1)和C(x2,y2),不妨設|AB|≤|AC|(這里的距離為曼哈頓距離),如下圖:?
?
|AB|=x1+y1,|AC|=x2+y2,|BC|=|x1-x2|+|y1-y2|。而由于B和C都在y軸向右45度的區域內,有y-x>0且x>0。下面我們分情況討論:?
1. x1>x2且y1>y2。這與|AB|≤|AC|矛盾;?
2. x1≤x2且y1>y2。此時|BC|=x2-x1+y1-y2,|AC|-|BC|=x2+y2-x2+x1-y1+y2=x1-y1+2*y2。由前面各種關系可得y1>y2>x2>x1。假設|AC|<|BC|即y1>2*y2+x1,那么|AB|=x1+y1>2*x1+2*y2,|AC|=x2+y2<2*y2<|AB|與前提矛盾,故|AC|≥|BC|;?
3. x1>x2且y1≤y2。與2同理;?
4. x1≤x2且y1≤y2。此時顯然有|AB|+|BC|=|AC|,即有|AC|>|BC|。?
綜上有|AC|≥|BC|,也即在這個區域內只需選擇距離A最近的點向A連邊。?
這種連邊方式可以保證邊數是O(N)的,那么如果能高效處理出這些邊,就可以用Kruskal在O(NlogN)的時間內解決問題。下面我們就考慮怎樣高效處理邊。?
我們只需考慮在一塊區域內的點,其他區域內的點可以通過坐標變換“移動”到這個區域內。為了方便處理,我們考慮在y軸向右45度的區域。在某個點A(x0,y0)的這個區域內的點B(x1,y1)滿足x1≥x0且y1-x1>y0-x0。這里對于邊界我們只取一邊,但是操作中兩邊都取也無所謂。那么|AB|=y1-y0+x1-x0=(x1+y1)-(x0+y0)。在A的區域內距離A最近的點也即滿足條件的點中x+y最小的點。因此我們可以將所有點按x坐標排序,再按y-x離散,用線段樹或者樹狀數組維護大于當前點的y-x的最小的x+y對應的點。時間復雜度O(NlogN)。?
至于坐標變換,一個比較好處理的方法是第一次直接做;第二次沿直線y=x翻轉,即交換x和y坐標;第三次沿直線x=0翻轉,即將x坐標取相反數;第四次再沿直線y=x翻轉。注意只需要做4次,因為邊是雙向的。?
至此,整個問題就可以在O(NlogN)的復雜度內解決了。

2 莫隊算法

據說這個算法是莫濤提出的(Orz!),但是在網上到處都搜不到相關資料,最后問pty才知道的。這個算法是用于處理一類不帶修改的區間查詢問題的離線算法,其核心在于利用曼哈頓距離最小生成樹算法對區間處理順序進行處理。比如下面這個例題(清橙A1206《小Z的襪子》,就是莫隊出的題):?
給定一個長為N的序列,每個元素的值是其顏色。有M次詢問,每次詢問從一個區間中隨機選取兩個元素同色的概率。?
一次詢問[l,r]的答案即,其中是區間中第i中顏色的個數。顯然暴力是O(NM)的,而且一般的區間問題的思路似乎不適用。?
我們先考慮一個簡化的問題:所有的查詢區間的左端點都是1。那么我們可以按右端點排序,假設已經處理出了[1,r]的答案,考慮轉移到[1,r+k],即添加k個元素,這個可以在O(k)的復雜度內求出。那么處理所有區間的復雜度(不考慮排序)就是O(N)。?
那么如果是從[l,r]轉移到[l’,r’]呢?復雜度即O(|r’-r|+|l’-l|),也即點(l,r)到點(l’,r’)的曼哈頓距離。那么如果將所有詢問轉化成二維平面中的點,求曼哈頓距離最小生成樹,再按照生成樹的順序做,就可以最小化區間之間轉移的復雜度。可以證明(我不會證……似乎莫隊的論文里有),這樣做的復雜度是O(N^1.5)的。問題也就得到了解決。

?

【BZOJ2038】小Z的襪子

傳送門?
寫在前面:莫隊竟如此暴力……?
思路:當初我對這個題的第一感覺——這個區間問題可以用線段樹或者樹狀數組?答案當然是不能,于是我就去簡單學了下莫隊算法。在我看來,莫隊(分塊版,不是二維曼哈頓距離什么什么最小生成樹)就是分塊排序優化暴力查找,減少查找區間之間的覆蓋長度,從而優化時間復雜度,有一種說法很精彩

如果我們已知[l,r]的答案,能在O(1)時間得到[l+1,r]的答案以及[l,r-1]的答案,即可使用莫隊算法。時間復雜度為O(n^1.5)。如果只能在logn的時間移動區間,則時間復雜度是O(n^1.5*log?
n)。 其實就是找一個數據結構支持插入、刪除時維護當前答案。

這道題的話我們很容易用數組來實現,做到O(1)的從[l,r]轉移到[l,r+1]與[l+1,r]。

那么莫隊算法怎么做呢?以下都是在轉移為O(1)的基礎下討論的時間復雜度。另外由于n與m同階,就統一寫n。?
如果已知[l,r]的答案,要求[l’,r’]的答案,我們很容易通過|l – l’|+|r – r’|次轉移內求得。

對于它的時間復雜度分析

將n個數分成sqrt(n)塊。 按區間排序,以左端點所在塊內為第一關鍵字,右端點為第二關鍵字,進行排序,也就是以(pos [l],r)排序?
然后按這個排序直接暴力,復雜度分析是這樣的:?
1、i與i+1在同一塊內,r單調遞增,所以r是O(n)的。由于有n^0.5塊,所以這一部分時間復雜度是n^1.5。?
2、i與i+1跨越一塊,r最多變化n,由于有n^0.5塊,所以這一部分時間復雜度是n^1.5?
3、i與i+1在同一塊內時變化不超過n^0.5,跨越一塊也不會超過n^0.5,忽略*2。由于有n個數,所以時間復雜度是n^1.5?
于是就是O(n^1.5)了

這道題是比較模板的莫隊分塊了,對于一個區間詢問[L,R],我們要求的ans是?
ans=(Σsum(color[i])?1)?sum(color[i])/2)/((R?L+1)?(R?L))?
簡化可得?
ans=(Σ(sum(color[i])2)?(R?L+1))/((R?L+1)?(R?L))?
其中sum(color[i])指第i種顏色在[L,R]中出現的次數?
那么我們現在求出各個詢問區間中sum(color[i])2就行了,具體實現方法參照代碼?
注意:?
1.當一種顏色數量ci增加1時,我們可以看出ans=ans?ci2+(ci+1)2,簡化可得ans=ans+(ci?2+1),同樣減少1時,ans=ans?ci2+(ci?1)2,簡化得ans=ans+(ci?2?1),這樣做的好處是減少乘法且可用位運算,優化常數(然而并沒有什么卵用)?
2.極限數據50000*50000如果不用longlong會教你做人←_←?
代碼:

1 #include"bits/stdc++.h" 2 #define LL long long 3 using namespace std; 4 int n,m,last_l=1,last_r; 5 LL ans,p; 6 int color[50010],block[50010]; 7 LL sum[50010]; 8 struct os 9 { 10 LL part,l,r,nume,deno;//nume指分子,deno指分母 11 }q[50010]; 12 int cmp1(os xx,os yy) 13 { 14 if (block[xx.l]<block[yy.l]) return 1; 15 if (block[xx.l]>block[yy.l]) return 0; 16 return xx.r<yy.r; 17 } 18 int cmp2(os xx,os yy){return xx.part<yy.part;} 19 inline LL gcd(LL x,LL y) 20 { 21 if (!y) return x; 22 return gcd(y,x%y); 23 } 24 main() 25 { 26 scanf("%d%d",&n,&m); 27 for (int i=1;i<=n;i++) scanf("%d",&color[i]); 28 block[0]=sqrt(n); 29 for (int i=1;i<=n;i++) 30 block[i]=(i-1)/block[0]+1; 31 for (int i=1;i<=m;i++) 32 scanf("%d%d",&q[i].l,&q[i].r), 33 q[i].part=i; 34 sort(q+1,q+m+1,cmp1); 35 36 for (int i=1;i<=m;i++) 37 { 38 q[i].deno=(q[i].r-q[i].l+1)*(q[i].r-q[i].l); 39 if (last_r<q[i].r) 40 { 41 for (int j=last_r+1;j<=q[i].r;j++) 42 ans+=((sum[color[j]]<<1)+1), 43 sum[color[j]]++; 44 } 45 if (last_r>q[i].r) 46 { 47 for (int j=last_r;j>q[i].r;j--) 48 ans-=((sum[color[j]]<<1)-1), 49 sum[color[j]]--; 50 } 51 if (last_l>q[i].l) 52 { 53 for (int j=last_l-1;j>=q[i].l;j--) 54 ans+=((sum[color[j]]<<1)+1), 55 sum[color[j]]++; 56 } 57 if (last_l<q[i].l) 58 { 59 for (int j=last_l;j<q[i].l;j++) 60 ans-=((sum[color[j]]<<1)-1), 61 sum[color[j]]--; 62 } 63 q[i].nume=ans-(q[i].r-q[i].l+1); 64 last_l=q[i].l; 65 last_r=q[i].r; 66 } 67 sort(q+1,q+m+1,cmp2); 68 for (int i=1;i<=m;i++) 69 { 70 if (!q[i].nume){printf("0/1\n");continue;} 71 p=gcd(q[i].nume,q[i].deno); 72 printf("%lld/%lld\n",q[i].nume/p,q[i].deno/p); 73 } 74 }

?

轉載于:https://www.cnblogs.com/Renyi-Fan/p/8137948.html

總結

以上是生活随笔為你收集整理的曼哈顿距离最小生成树与莫队算法(总结)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。