BZOJ1023: [SHOI2008]cactus仙人掌圖(仙人掌)
阿新 • • 發佈:2018-08-11
sam content 怎麽 最長路 class .com col 單調隊列 重復
15 3
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
5 2 14 9 15 10 8
解題思路 第一次接觸仙人掌的蒟蒻QAQ 今天本來想學一下圓方樹,然而還沒學到怎麽建就卡在了這道題上。 這是一道仙人掌入門題,思路也比較樸素。
對於一顆仙人掌,我們最不容易處理的就是環,對於一個環,我們視為一個點雙連通分量。 所以我們使用tarjan 因為一個不在環內的點和環的頂點都可以直接更新答案。 答案用最長路徑+子節點最長路徑+1更新。 這個點的最長路徑用子節點最長路徑+1更新。 註意順序! 在一個環的頂點將整個環抽出(因為是一個環,所以抽出後復制一遍成為一個兩倍的鏈)
然後DP就可以啦
最長路徑可以被中間鏈+子節點最長路徑更新
這部分需要使用單調隊列維護
最後更新頂點即可^_^
Description
如果某個無向連通圖的任意一條邊至多只出現在一條簡單回路(simple cycle)裏,我們就稱這張圖為仙人掌
圖(cactus)。所謂簡單回路就是指在圖上不重復經過任何一個頂點的回路。
舉例來說,上面的第一個例子是一張仙人圖,而第二個不是——註意到它有三條簡單回路:(4,3,2,1,6
,5,4)、(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同時出現在前兩
個的簡單回路裏。另外,第三張圖也不是仙人圖,因為它並不是連通圖。顯然,仙人圖上的每條邊,或者是這張仙
人圖的橋(bridge),或者在且僅在一個簡單回路裏,兩者必居其一。定義在圖上兩點之間的距離為這兩點之間最
短路徑的距離。定義一個圖的直徑為這張圖相距最遠的兩個點的距離。現在我們假定仙人圖的每條邊的權值都是1
,你的任務是求出給定的仙人圖的直徑。
Input
輸入的第一行包括兩個整數n和m(1≤n≤50000以及0≤m≤10000)。其中n代表頂點個數,我們約定圖中的頂
點將從1到n編號。接下來一共有m行。代表m條路徑。每行的開始有一個整數k(2≤k≤1000),代表在這條路徑上
的頂點個數。接下來是k個1到n之間的整數,分別對應了一個頂點,相鄰的頂點表示存在一條連接這兩個頂點的邊
。一條路徑上可能通過一個頂點好幾次,比如對於第一個樣例,第一條路徑從3經過8,又從8返回到了3,但是我們
保證所有的邊都會出現在某條路徑上,而且不會重復出現在兩條路徑上,或者在一條路徑上出現兩次。
Output
只需輸出一個數,這個數表示仙人圖的直徑長度。
Sample Input
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
5 2 14 9 15 10 8
Sample Output
8解題思路 第一次接觸仙人掌的蒟蒻QAQ 今天本來想學一下圓方樹,然而還沒學到怎麽建就卡在了這道題上。 這是一道仙人掌入門題,思路也比較樸素。
對於一顆仙人掌,我們最不容易處理的就是環,對於一個環,我們視為一個點雙連通分量。 所以我們使用tarjan 因為一個不在環內的點和環的頂點都可以直接更新答案。 答案用最長路徑+子節點最長路徑+1更新。 這個點的最長路徑用子節點最長路徑+1更新。 註意順序! 在一個環的頂點將整個環抽出(因為是一個環,所以抽出後復制一遍成為一個兩倍的鏈)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 struct pnt{ 6 int hd; 7 int fa; 8 int dfn; 9 int low; 10 int mxc; 11 }p[1000000]; 12 struct ent{ 13 int twd; 14 int lst; 15 }e[1000000]; 16 int cnt; 17 int n,m,k; 18 int trc; 19 int ans; 20 int crt; 21 int crl[1000000]; 22 int q[1000000]; 23 int h,t; 24 void ade(int f,int t) 25 { 26 cnt++; 27 e[cnt].twd=t; 28 e[cnt].lst=p[f].hd; 29 p[f].hd=cnt; 30 } 31 void ringbrk(int st,int fi) 32 { 33 crt=0; 34 while(fi!=st) 35 { 36 crl[++crt]=p[fi].mxc; 37 fi=p[fi].fa; 38 } 39 crl[++crt]=p[st].mxc; 40 for(int i=1;i<crt;i++) 41 crl[crt+i]=crl[i]; 42 h=t=1; 43 q[1]=1; 44 int ln=crt/2; 45 for(int i=2;i<=crt+ln;i++) 46 { 47 while(h<=t&&i-q[h]>ln) 48 h++; 49 ans=max(ans,crl[q[h]]+crl[i]+i-q[h]); 50 while(h<=t&&crl[q[t]]+i-q[t]<=crl[i]) 51 t--; 52 q[++t]=i; 53 } 54 for(int i=1;i<crt;i++) 55 { 56 p[st].mxc=max(p[st].mxc,crl[i]+min(i,crt-i)); 57 } 58 } 59 void tarjan(int x) 60 { 61 p[x].dfn=p[x].low=++trc; 62 for(int i=p[x].hd;i;i=e[i].lst) 63 { 64 int to=e[i].twd; 65 if(to==p[x].fa)continue; 66 if(!p[to].dfn) 67 { 68 p[to].fa=x; 69 tarjan(to); 70 p[x].low=min(p[x].low,p[to].low); 71 if(p[x].dfn<p[to].low) 72 { 73 ans=max(ans,p[x].mxc+p[to].mxc+1); 74 p[x].mxc=max(p[x].mxc,p[to].mxc+1); 75 } 76 }else{ 77 p[x].low=min(p[x].low,p[to].low); 78 } 79 } 80 for(int i=p[x].hd;i;i=e[i].lst) 81 { 82 int to=e[i].twd; 83 if(p[to].fa!=x&&p[to].dfn>p[x].dfn) 84 { 85 ringbrk(x,to); 86 } 87 } 88 } 89 int main() 90 { 91 scanf("%d%d",&n,&m); 92 for(int i=1;i<=m;i++) 93 { 94 int frm,twd,nm; 95 scanf("%d%d",&nm,&frm); 96 for(int j=1;j<nm;j++) 97 { 98 scanf("%d",&twd); 99 ade(twd,frm); 100 ade(frm,twd); 101 frm=twd; 102 } 103 } 104 tarjan(1); 105 printf("%d\n",ans); 106 return 0; 107 }
BZOJ1023: [SHOI2008]cactus仙人掌圖(仙人掌)