暑假 樹狀陣列 I Japan

2021-07-04 13:06:08 字數 1614 閱讀 3718

題意:在西邊有m座城市,東邊有n座城市,分別都是從北到南編號依次為1,2,3...(n/m)

要建k條高速公路,每條高速公路分別從西邊的一座城市連線到東邊的一座城市。

問:這些高速公路有多少個交叉點。

的高速公路有2中情況,(1)從西邊編號比x小的城市連線到東邊比y大的城市。(2)從西邊

編號比x大的城市鏈結到東邊比y小的城市。 我們可以把每一條高速公路看成二維座標裡的

乙個點(x,y)。那個與它相交的高速公路的點(xi,yi)為:點(x,y)左上方和右下方的點的個數。

簡單來說就是滿足:(x-xi)*(y-yi)<0,那麼這兩個點(兩條高速公路)就是相交的。

但是:由於n,m最大值為1000,如果n個每個城市都與m的每個城市有高速公路,那麼總的

高速公路條數為1000*1000。直接暴力求會tle。

tle暴力**:

#includeusing namespace std;

const int maxn = 1000 + 5;

struct point

;point city[maxn*maxn];

int main()

for (int i = 1; i <= k; i++)

}} cout << "test case" << ++ans << ": " << sum << endl;

} return 0;

}

既然要求點(x,y)左上方和右下方的點的個數(之和再除以2,因為對於每條高速公路會被計算2次,那麼可以統一只求一邊)。

那麼可以通過預處理(x軸公升序排序)+只求點左上方的點的個數。

ac**:

/*

排序之後對於每個點(x,y)都會出現在之前點的右邊,

即固定了乙個變數(x),只需要求另乙個變數(y)即可,

樹狀陣列c就是求y軸的點出現的個數。

*/#include#include#includeusing namespace std;

const int maxn = 1000 + 5;//城市上限

struct point

;point city[maxn*maxn];

//高速公路上限為maxn*maxn

int c[maxn];//樹狀陣列

int lowbit(int x)//樹狀陣列函式之一

long long int sum(int i)//樹狀陣列函式之一

return s;

}bool cmp(point a, point b)//比較函式

return a.x < b.x;

}void add(int i, int val)//樹狀陣列函式之一

}int main()

sort(city, city + k, cmp);//按x軸公升序

for (int i = 0; i < k; i++)

printf("test case %d: %lld\n", ++ans, temp);

} return 0;

}

巧妙地將一些二元關係轉換成二維座標點,簡化問題。

知道點的總是+上方點的數目,即可求出下方點的數目。

暑假 樹狀陣列 F Brainman

又是一道逆序數的問題。題意 給出乙個序列,每次只能交換相鄰的2個位置的數,問最少經過幾次交換可以使得序列遞增 思路 逆序對問題,求每個數後面有多少個數比它小 樹狀陣列 離散化 include include includeusing namespace std const int maxn 5000...

暑假 樹狀陣列 E Stars

題意 給出一些星星的橫座標和縱座標,而且星星的縱座標按非遞減排列,如果縱座標相等,則橫座標按遞增排列,任意兩顆星星不會重合。某一顆星星的level為 這顆星星的左下角 包括x相等但y小,y相等但x小 的星星個數。思路 設定乙個變數m標記它原始的位置,然後按x軸排序,每顆星星的level為 星星原始位...

樹狀陣列(暑假選拔)

某天小y家門前突然多出了兩座石塔,這兩座石塔妨礙了小x的出行,現在小x想要破壞這兩座石塔,假設兩座石塔分別由n1與n2塊石頭構成,每一塊石頭都有乙個破壞順序的優先順序,並且保證這兩座石塔中沒有兩塊優先順序一樣的石頭,小x覺得優先順序越高的石頭應該越早破壞掉,小x可以每次從任意一座石塔的塔頂移動一塊石...