標籤:style blog http color io 資料 for ar
首先還是要清楚一下堆操作的代碼,畢竟線段樹打多了,打堆的時候總會往線段樹方向靠近
首先是建堆:
D=1;
for(;D<maxn+2;D<<=1);
然後給堆賦予值就可以了
尋找區間段的和:
int query(int s,int t)
{
int i=D+s-1,j=D+t+1,ans=0;
for(;i^j^1;i>>=1,j>>=1){
if(~i&1) ans+=sum[i^1];
if(j&1) ans+=sum[j^1];
}
return ans;
}
更新操作:
void update(int i)
{
for(;i^1;i>>=1)
sum[i>>1]=sum[i]+sum[i^1];
}
之前也做了一道star level的題寫成了部落格,這裡繼續來寫一遍,就是問對於一個星星的位置,比其x小於等於和y小於等於的點有多少個
這裡我們所採取的是先進行一維上的排序,然後排好序後用另一維度來建樹
如星星的題目已經以y的大小先後排好序了,那我們就省事了
我們從第一個節點不斷添加進去,來找比它x小的數有幾個,每次添加一個x,都要tree[D+x]++,再進行更新操作,因為後面的點是絕對不會影響到前面的點的
所以是可以這樣做的:
第二題:
SPOJ RATING
這道題目也是兩個維度,不過如果出現一樣的值的話,者之間是不算誰比誰大的,這是跟星星不一樣的地方
所以我們排好序後,每次添加點進入的時候還需要判斷是否與前一個點值完全相同,如果相同不訪問,直接繼承前面一個點的值就可以了,然後再做更新
同時星星的點是題目本身按順序給出的,而這裡是亂序的,我們需要事先排好序然後不斷添入點
我採取的方法是,建立結構體,除2維的資料外,還需記錄id號,不然沒法記錄每個位置比別人大的個數
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define N 300005 6 int sum[N<<2],D,maxn; 7 struct Edge{ 8 int x,y,id; 9 bool operator<(const Edge &m)const10 {11 return x==m.x?y<m.y:x<m.x;12 }13 }e[N];14 void update(int i)15 {16 for(;i^1;i>>=1)17 sum[i>>1]=sum[i]+sum[i^1];18 }19 int query(int s,int t)20 {21 int i=D+s-1,j=D+t+1,ans=0;22 for(;i^j^1;i>>=1,j>>=1){23 if(~i&1) ans+=sum[i^1];24 if(j&1) ans+=sum[j^1];25 }26 return ans;27 }28 int main()29 {30 int n,ans[N];31 maxn=0;32 memset(sum,0,sizeof(sum));33 scanf("%d",&n);34 for(int i=0;i<n;i++){35 scanf("%d%d",&e[i].x,&e[i].y);36 maxn=max(maxn,e[i].y);37 e[i].id=i;38 }39 D=1;40 for(;D<maxn+2;D<<=1);41 sort(e,e+n);42 int k;43 for(int i=0;i<n;i++){44 if(i>1&&e[i].x==e[i-1].x&&e[i].y==e[i-1].y){45 }46 else{47 k=query(1,e[i].y);48 }49 ans[e[i].id]=k;50 sum[D+e[i].y]++;51 update(D+e[i].y);52 }53 for(int i=0;i<n;i++)54 printf("%d\n",ans[i]);55 return 0;56 }