道路維護【長郡NOIP2014模擬10.22】

Description

最近徆多人投訴說C國的道路破損程度太大,以至亍無法通行
C國的政府徆重視這件事,但是最近財政有點緊,丌可能將所有的道路都進行維護,所以他們決定按照下述方案進行維護
將C國抽象成一個無向圖,定義兩個城市乊間的某條路徑的破損程度爲該條路徑上所有邊破損程度的最大值,定義兩個城市乊間的破損程度爲兩個城市乊間所有路徑破損程度的最小值
然後C國政府向你提問多次,有多少個城市對的破損程度丌超過L,他們將依照你的回答來決定到底怎樣維護C國的道路

Input

第一行三個數n,m,q,表示圖的點數和邊數以及政府的詢問數
以下m行每行三個數a,b,c,表示一條連接a,b且破損程度爲c的無向邊
接下來一行q個數Li,表示詢問有多少個城市對的破損程度丌超過Li

Output

一行q個數,對應每個詢問,輸出滿足要求的城市對的數目

Sample Input

4 8 8
1 4 0
3 4 9
4 4 9
1 2 10
3 1 8
1 2 6
4 2 7
1 2 5
4 10 8 1 6 7 7 9

Sample Output

1 6 6 1 3 3 3 6
【友情提示】
一個城市對(i,j),滿足i

Data Constraint

30%數據滿足n≤10^2,m≤10^3,q≤10^2
60%數據滿足n≤10^2,m≤10^3,q≤10^5
100%數據滿足n≤10^4,m,q≤10^5,0≤c,Li≤10^9


思路

考場上先是看錯題了。。。。。不過並沒有什麼影響。
想的是預處理答案二分查找,不過竟然爆空間了。。
然後想到離線,不過沒時間了。


解法

30%:n^3的Floyd求當前圖的所有點之間的路徑長度,然而判斷即可。時間O(n^3+qn^2).
60%:
對於上面30分做法,我們發現查詢部分太大,所以把兩點間距離預處理出來後,可以排一次序。對於查詢,二分查找即可。時間O(n^3+qlog(n^2))
100%:n到1e3後會爆空間,且Floyd也過不了。
隨着非遞減的邊的加入,同一塊裏的點互相之間的破損程度是非遞減的,加上空間問題,可以考慮離線+並查集。
先把邊離線出來按邊的破損從小到大排一次序。
把詢問也按照破損程度從小到大拍一次序。
對於一個詢問,我們把破損程度小於等於這個詢問的邊逐漸加入,然後把其兩端的聯通塊x,y並起來。
若x,y本來就是聯通的,那麼答案不會有影響。
若x,y本身不連通,那麼聯通這兩個聯通塊,同時會造成新的合法點對數量爲sum[x]*sum[y](sum[x]表示x聯通塊的大小)。
時間:O(n+q)(主體)+O(3n log n)(排序)。


代碼

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)

using namespace std;

const int maxn=1e4+5,maxm=1e5+5;
int dad[maxn],sum[maxn];
struct cy{
    int s,t,val;
}a[maxm];
struct hg{
    int val,id,ans;
}que[maxm];
int n,m,q,num,tot,nn;

bool cmp1(cy a,cy b)
{
    return a.val<b.val;
}
bool cmp2(hg a,hg b)
{
    return a.val<b.val;
 }
 bool cmp3(hg a,hg b)
 {
    return a.id<b.id;
 }
int getdad(int x)
{
    if (dad[x]==x) return x;
    else {
        dad[x]=getdad(dad[x]);
        return dad[x];
    }
}
int main()
{
    //freopen("T1.in","r",stdin);
//  freopen("T1.out","w",stdout);
    scanf("%d%d%d",&n,&m,&q);
    fo(i,1,m){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if (x==y) continue;
        a[++tot].s=x,a[tot].t=y,a[tot].val=z;
    }
    sort(a+1,a+tot+1,cmp1);

    fo(i,1,n) dad[i]=i,sum[i]=1;

    fo(i,1,q) scanf("%d",&que[i].val),que[i].id=i;
    sort(que+1,que+1+q,cmp2);

    num=1;nn=0;
    fo(i,1,q){
        int now=que[i].val;
        while (a[num].val<=now&&num<=tot) {
            int x=a[num].s,y=a[num].t;
            int X=getdad(x),Y=getdad(y);
            if (X!=Y) {
                nn+=sum[Y]*sum[X];
                sum[Y]+=sum[X]; sum[X]=0;
                dad[X]=Y;
            }
            ++num;
        }
        que[i].ans=nn;
    }

    sort(que+1,que+1+q,cmp3);
    fo(i,1,q) printf("%d ",que[i].ans);
} 

這裏寫圖片描述

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