題意:在西邊有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可以每次從任意一座石塔的塔頂移動一塊石...