3067 Japan (樹狀陣列 思維)
阿新 • • 發佈:2018-12-09
題意:
日本東海岸有N個城市(從北到南命名為1, 2, ..., N),西海岸有M個城市(從北到南命名為1, 2, ..., M),東西之間有K條高速公路,問這K條高速公路有多少個交叉點(一個交叉點有且只有兩條高速公路經過)(1000 <= N, M <= 1000)。
題解:
記每條高速公路為(x,y), 即東岸的第x個城市與西岸的第y個城市修一條路。當兩條路有交點時,滿足(x1-x2)*(y1-y2) < 0。所以,將每條路按x從小到達排序,若x相同,按y從小到大排序。 然後按排序後的公路用樹狀陣列線上更新,求y的逆序數之 和 即為交點個數。
題目沒給k的範圍,沒給T的範圍......
自己試了一下這個題陣列開到1e6就過了,1e5還不行,最後的結果需要開long long
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define maxn 400010 #define pr printf using namespace std; #define ll long long #define pr pair<int,int> #define maxn 1000000 pr a[maxn]; int c[maxn]; int n,m,k; bool cmp(pr x,pr y) { if(x.first==y.first) return x.second<y.second; return x.first<y.first; } inline int lowbit(int x) { return x & -x; } inline void add(int i,int val) { while(i<=m) { c[i]+=val; i+=lowbit(i); } } inline int sum(int i) { int s=0; while(i>0) { s+=c[i]; i-=lowbit(i); } return s; } int main() { //freopen("input.txt","r",stdin); int T; scanf("%d",&T); for(int cas=1;cas<=T;++cas) { for(int i=0;i<=maxn;++i) c[i]=0; //memset(c,0,sizeof(c)); scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=k;++i) scanf("%d%d",&a[i].first,&a[i].second); sort(a+1,a+1+k,cmp); ll ans=0; for(int i=1;i<=k;++i) { add(a[i].second,1);//有點的地方就是1,沒點的地方就是0 ans+=i-sum(a[i].second); } printf("Test case %d: %lld\n",cas,ans); } return 0; }