csu1335 高橋與低橋

Description

有個腦筋急轉彎是這樣的:有距離很近的一高一低兩座橋,兩次洪水之後高橋被淹了兩次,低橋卻只被淹了一次,爲什麼?答案是:因爲低橋太低了,第一次洪水退去之後水位依然在低橋之上,所以不算“淹了兩次”。舉例說明:

假定高橋和低橋的高度分別是5和2,初始水位爲1

第一次洪水:水位提高到6(兩個橋都被淹),退到2(高橋不再被淹,但低橋仍然被淹)

第二次洪水:水位提高到8(高橋又被淹了),退到3。

沒錯,文字遊戲。關鍵在於“又”的含義。如果某次洪水退去之後一座橋仍然被淹(即水位不小於橋的高度),那麼下次洪水來臨水位提高時不能算“又”淹一次。

輸入n座橋的高度以及第i次洪水的漲水水位ai和退水水位bi,統計有多少座橋至少被淹了k次。初始水位爲1,且每次洪水的漲水水位一定大於上次洪水的退水水位。

Input

輸入文件最多包含25組測試數據。每組數據第一行爲三個整數n, m, k(1<=n,m,k<=105)。第二行爲n個整數hi(2<=hi<=108),即各個橋的高度。以下m行每行包含兩個整數ai和bi(1<=bi<ai<=108, ai>bi-1)。輸入文件不超過5MB。

Output

對於每組數據,輸出至少被淹k次的橋的個數。

Sample Input

2 2 22 56 28 35 3 22 3 4 5 65 34 25 2

Sample Output

Case 1: 1Case 2: 3

Hint

Source

湖南省第九屆大學生計算機程序設計競賽


思路:這道題思路比較清晰,需要對各個橋記錄上次退潮時的狀況,是否任然處於被淹狀態,還要與下次漲潮時的高度對比並記錄,這樣算起來時間複雜度爲O(n^n);絕對會TE,

這裏要藉助樹狀數組的知識來解決,靈活的處理數據把複雜度降爲(Onlogn),但注意不是照搬板子,難度就在這裏。需要自己寫出幾個函數。算法還是要理解清楚,不能照搬板子,我這次都看不出來要用樹狀數組。。。。
如果有點難理解爲什麼sum()函數裏面爲什麼要累加一段區間的c[p],可以去看下樹狀數組的定義,因爲第i座橋控制的用來表達它被淹記錄的,不是一個c數組單元,而是一段區間。其他比如說add(),search()也是這個道理    。
具體見代碼註釋;
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=1e5+5;
int n,m,k;
int a[maxn],c[maxn],x[maxn],y[maxn];
int lowbit(int k1)
{
    return k1&(-k1);
}
int add(int p,int q)//對某一座橋被淹次數進行操作
{
    while(p>0)
    {
        c[p]+=q;
        p-=lowbit(p);
    }
    return 0;
}
//int count1=1;
int search1(int p)//二分查找到指定位置
{
    int mid,temp=p;
    int rs=n,ls=1;
    while(rs>ls)
    {
        mid=((rs+ls)>>1);
        if(a[mid]>=temp)
        {
            rs=mid;
        }
        else ls=mid+1;
    }
    return rs;
}
int sum(int p)//求出p位置總共被淹了幾次
{
    int kk=0;
    while(p<=n)
    {
        kk+=c[p];
        p+=lowbit(p);
    }
    return kk;
}
int main()
{
    int cnt=0;
    while(scanf("%d %d %d",&n,&m,&k)!=EOF)
    {
        memset(c,0,sizeof(c));

        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);

        sort(a+1,a+n+1);
        int p,q,ans,kk;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            //cout<<x[i]<<" "<<y[i]<<endl;
            if(i==1)
            {
                p=i;
                q=search1(x[i]);
                //printf("")
                //cout<<123456<<endl;
            }
            else
            {
                p=search1(y[i-1]);//找到上次退潮橋被淹的橋的最高序號,因爲拍過序p,所以小與p的都不用加次數,因爲都在水裏
                q=search1(x[i]);//找到比這次漲潮高度要淹的最高序號q,q與q之下的都要被淹
            }
            add(p,-1);//對小與上次退潮高度的橋被淹次數減1,抵消下面的加1操作
            add(q,1);//對小與這次漲潮高度的橋被淹次數加1
        }
        ans=0;
        for(int i=1;i<=n;i++)
        {

            kk=sum(i);
            //cout<<kk<<" "<<k<<endl;
            if(kk>=k)
            ans++;
        }
        printf("Case %d: %d\n",++cnt,ans);
    }
}









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章