憂桑三角形
試題描述
小j是一名文化課選手,他十分喜歡做題,尤其是裸題。有一棵樹,樹上每個點都有點權,現在有以下兩個操作:
1. 修改某個點的點權
2. 查詢點u和點v構成的簡單路徑上是否能選出三個點組成三角形
輸入
第一行兩個整數n,q,代表點數和詢問數。第二行n個整數表示點權。下面n-1行每行兩個整數a,b代表a,b之間有一條邊。下面q行每行3個整數t,a,b:若t=0,詢問(a,b);否則將點a的權值修改為b
輸出
對於每個詢問輸出y表示能構成三角形,輸出n表示不能構成三角形
輸入示例
5512345
1223
3415
0130
4511
4025
023
輸出示例
nyyn
資料範圍
對於30%的資料有n, q ≤ 1000
對於100%的資料有n, q ≤ 105,點權範圍在32位整數範圍內
orz wzj,方法超級機智。注意到「點權範圍在32位整數範圍內」這句話,這是個突破口,它告訴我們a和b距離很長的時候,一定能組成乙個三角形,為什麼呢?我們不妨寫個程式算算。
設經過的點權值序列為f,將f從大到小排序後,根據三角形三遍關係得到最好情況下fi = fi-1 + fi-2(i > 2),於是可以寫乙個求f序列前50位的**(為了迎合題目資料範圍,我把f序列也定義為32位整型變數,下面用了乙個滾動陣列,f被壓縮成了f1和f2):
#define maxn 51intmain()
return0;
}
(標頭檔案自己加去吧……)
執行一下,結果如下:
11235813
2134
5589
144233
377610
9871597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
1346269
2178309
3524578
5702887
9227465
14930352
24157817
39088169
63245986
102334155
165580141
267914296
433494437
701408733
1134903170
1836311903 -1323752223
512559680 -811192543 -298632863 -1109825406 -1408458269
第47個數是負數,也就是說這個f序列長度超不過47
所以演算法來了:當a與b之間距離大於50時,直接輸出y,否則記錄下路徑所經過的節點權值然後排序處理。
如何找a與b之間的距離呢?
這裡有乙個思想上的易錯點,你可能會想到dfs序判斷祖先關係,當a是b的祖先時,說明在根節點同側,所以用它們的深度相減,否則深度相加得到距離。乍一看思想很正確,我也因此除錯半天……然而當他們的最近公共祖先(lowest common ancestors,lca)不是根節點時,第二種情況深度相加就不能得到正確距離了(想一想,為什麼)。
(你不知道什麼叫最近公共祖先?對於有根樹t的兩個結點u、v,它們的最近公共祖先是乙個結點x,滿足x是u、v的祖先且x的深度盡可能大。)
所以正確姿勢是:只能好好寫倍增演算法求lca了……
略略講一下lca求法。顯然直接dfs是o(n)級別,會超時的,所以我們可以設fa(u, x)表示節點u的第2x級祖先,不難得到遞推式:fa(u, x) = fa(fa(u, x-1), x-1)
你知道為什麼要出現「第2x級祖先」嗎?對於一條很長的鏈,我們可以把它看成乙個序列,乙個序列是可以分成若干個個數為2n(n∈z+)的段的,就像乙個數可以表示成二進位制一樣,所以一條鏈我們不必乙個節點乙個節點地走,而是可以一下跳2n個節點,而分後的序列數是log2(n)級別的,所以鏈上跳的步數也是log2(n)級別的。
回答詢問怎麼做呢?對於給定的a和b,先把它們搞到同乙個深度去,不妨設a深度大於b深度,所以我們就需要用上面所講的「跳節點」的方式把節點a跳到節點b統一深度去。接下來判斷:若a和b重合了,那麼顯然答案就是當前的b;否則還需要再進一步尋找,讓a與b同時用「跳節點」的方式向上走,直到它們的父親(即1級祖先,fa(u, 0))相同時(注意這裡為什麼是父親相同,而不是自身相同,請讀者思考),那麼答案就是當前結點a或b的父節點了。
怎麼樣?我們可以在o(logn)的時間內求出lca了,是不是感覺棒棒噠,為自己鼓鼓掌!(- -|||)
#include #include#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
intread()
while(isdigit(c))
return x *f;
}#define maxn 200010
#define maxlog 19
#define maxm (maxn << 1)
#define ll long long
intn, q, val[maxn], m, head[maxn], next[maxm], to[maxm];
void addedge(int a, int
b) stack
s; // 人工棧需要
bool
vis[maxn];
intdep[maxn], fa[maxn][maxlog], tot;
void build(int
s) }
else
s.pop();
}return;}
int query(int a, int
b) // 再一起向上找祖先
return a == b ? a : fa[a][0
]; // a = b說明它們在同一條鏈上,不在一條鏈上時最後答案是他們的父親(想一想,為什麼)
}int
path[maxn], cnt;
intmain()
if(dis < 3)
cnt = 0
; // 記錄a到b簡單路徑上各邊權值
while(a != c)
while(b != c)
path[++cnt] =val[c];
sort(path + 1, path + cnt + 1
);
bool ok = 0
;
for(int i = 1; i < cnt - 1; i++) if((ll)path[i] + path[i+1] > (ll)path[i+2
]) puts(ok ? "
y" : "n"
); }
}return0;
}
求大三角形中三角形個數
一道筆試程式設計題要求求乙個大三角形中所有小三角形的個數,大約是下面這種情況 首先想到是的將問題由求邊長為n的三角形個數 求邊長為n 1的三角形個數 求邊長為1的三角形個數 1,回溯求得所有三角形個數。但是再仔細一看因為有重疊三角形和倒置的三角形,所以這個方法不可行。接著找到三角形個數由三部分組成 ...
經典演算法 (三)帕斯卡三角形(楊輝三角形)
楊輝三角,是二項式係數在三角形中的一種幾何排列。在歐洲,這個表叫做帕斯卡三角形。帕斯卡 1623 1662 是在1654年發現這一規律的,比楊輝要遲393年,比賈憲遲600年。簡介 楊輝三角,是二項式係數在三角形中的一種幾何排列。在歐洲,這個表叫做帕斯卡三角形。帕斯卡 1623 1662 是在165...
三角形面積
算是自己第一道正式寫的演算法幾何吧,先從簡單的開始吧,加油!描述 給你三個點,表示乙個三角形的三個頂點,現你的任務是求出該三角形的面積 輸入 每行是一組測試資料,有6個整數x1,y1,x2,y2,x3,y3分別表示三個點的橫縱座標。座標值都在0到10000之間 輸入0 0 0 0 0 0表示輸入結束...