【廣東工業大學程序設計競賽決賽】tmk找三角

個人感覺這道題還是很有營養的,YY能力得到大幅度提高。

題目鏈接:http://gdutcode.sinaapp.com/problem.php?cid=1057&pid=5

樓主弱雞是當時跟着一起搞這場比賽的,1個半鍾邊刷榜邊過了4題。。他們服務器太弱,跑題跑太慢了。。就沒心情搞下去了。。

然後開始YY這道題,用了各種YY功力都沒有yy過他的巨大數據應該如何處理。。直到如今才腦洞大開。


題意:題目上是說,在一個圖上,某東西需要走最短路,然後問他要從s走到t,問走的這條路線上的所有邊能否有三條邊構成三角形。其實這個人走的路都是套路。因爲圖是一個生成樹,所以,無論怎麼走都是最短路。。。

然後這題套路深就深在,他的點很多1e5,邊值看起來並沒有什麼用1e9,其實。。這東西纔是關鍵,對於1e9範圍內,如果算去邊,最多能剩下多少條邊使他們不能構成三角形。這道題看起來就像ccpc長春現場賽的一道題。。當時有腦洞。。現在沒腦洞了。。想要構成最多條不能構成三角形的一個區間,只需要區間內所有數都滿足斐波那契序列即可,因爲三角形兩邊之和一定大於第三邊,所以滿足斐波那契序列的一定構不成三角形。

所以,對於1e9以內,可以構成多少不能構成三角形的。。好像50條是最多了。。所以。只要超過50條邊,他們一定能構成三角形(我列個擦哦)。所以這個東西可以完美解決常數的訪問量1e5,每次訪問我們最多隻用走50條邊。

然後這個考慮完了之後,我們還需要考慮一個黑科技,就是如何才能最快的在一棵樹內找到兩點的所有邊。這個對於一個節點無規律的樹來說是很有難度的。但是對於一棵滿足最大堆的樹來說,是很簡單的,只要每一層的數都比上一層的數大,我們訪問的時候就能夠通過比較兩個節點當前點的權值,來判斷他們誰應該向上移動,這樣的訪問速度爲他們之間的邊的條數,而他們的邊又只有50條,所以更加完美解決這道題的數據。

然而如何才能構造出這樣子的樹呢,其實只需要bfs一次,從1這個結點往下一層一層給id,保證上一層的id小於當前層任意一個點的id即可(由於我比較弱,只能想到這種寫法,若有大佬有其他寫法請指教)

本人的構圖能力比較差,可能寫出來有垃圾代碼。。各位多見諒,一定虛心學習構圖能力。。畢竟邊點的構建我刪了又寫了好幾次。。。

附上弱弱的代碼:

#include <bits/stdc++.h>

#define MAXN 100005

using namespace std;

struct Edge{
    int from,to,weight;
    Edge(int _from = 0,int _to = 0,int _weight = 0) : from(_from),to(_to),weight(_weight){}
};

struct Point{
    int pre,index,u;
    vector<Edge> v;
}p[MAXN];

int dis[MAXN];

void addEdge(int u,int v,int w){
    p[u].v.push_back(Edge(u,v,w));
}

void bfs(){
    queue<Point> q;
    q.push(p[1]);
    int idx = 1;
    p[1].index = idx;
    while(!q.empty()){
        Point tmp = q.front();
        q.pop();
        for(int i = 0;i < tmp.v.size();i++){
            if(tmp.v[i].to == tmp.pre){
                continue;
            }
            p[tmp.v[i].to].pre = tmp.u;
            p[tmp.v[i].to].index = ++idx;
            dis[tmp.v[i].to] = tmp.v[i].weight;
            q.push(p[tmp.v[i].to]);
        }
    }
}

void solve(int a,int b){
    vector<int> vs;
    int x = p[a].index,y = p[b].index;
    while(vs.size() < 50 && x != y){
        if(x > y){
            x = p[p[a].pre].index;
            vs.push_back(dis[a]);
            a = p[a].pre;
        } else {
            y = p[p[b].pre].index;
            vs.push_back(dis[b]);
            b = p[b].pre;
        }
    }
    bool flag = false;
    if(vs.size() == 50){
        printf("Yes\n");
        flag = true;
    } else {
        sort(vs.begin(),vs.end());
        for(int i = 2;i < vs.size();i++){
            if(vs[i - 2] + vs[i - 1] > vs[i]){
                printf("Yes\n");
                flag = true;
                break;
            }
        }
    }
    if(!flag){
        printf("No\n");
    }
}

void init(int n){
    for(int i = 0;i <= n;i++){
        p[i].v.clear();
    }
}

int main(){
    int T,a,b,u,v,w,n,q;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        init(n);
        for(int i = 1;i <= n;i++){
            p[i].u = i;
        }
        for(int i = 0;i < n - 1;i++){
            scanf("%d %d %d",&u,&v,&w);
            addEdge(u,v,w);
            addEdge(v,u,w);
        }
        bfs();
        scanf("%d",&q);
        while(q--){
            scanf("%d %d",&a,&b);
            solve(a,b);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章