個人感覺這道題還是很有營養的,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);
}
}
}