UOJ 416 APIO2018 鐵人兩項

2022-03-31 14:43:55 字數 1639 閱讀 1140

完了完了sb選手tarjan寫掛。

考慮先tarjan縮個點雙建個圓方樹。

然後發現,確定起點和終點後,中間點的可選方案數就是   這條路徑上的所有點雙 size 之和-2 。

定義原點表示原圖中的點,方點表示圓方樹中新加入的點。

這個東西可以轉化為路徑上的方點度數之和減去原點個數。

定義點 x 的權值 d[x] ,當 x 為圓點時 d[x] = -1,否則 d[x] 等於 x 的度數。

設起點終點都是圓點的經過點 x 的路徑條數為 c[x],那麼點 x 對答案的貢獻就是 d[x] * c[x] 。

時間複雜度 $o(n)$。

#include #define clr(x) memset(x,0,sizeof (x))

#define for(i,a,b) for (int i=a;i<=b;i++)

#define fod(i,b,a) for (int i=b;i>=a;i--)

#define pb(x) push_back(x)

#define mp(x,y) make_pair(x,y)

#define fi first

#define se second

#define real __zzd001

#define _seed_ ('c'+'l'+'y'+'a'+'k'+'i'+'o'+'i')

#define outval(x) printf(#x" = %d\n",x)

#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")

#define outtag(x) puts("----------"#x"----------")

#define outarr(a,l,r) printf(#a"[%d...%d] = ",l,r);\

for(_v2,l,r)printf("%d ",a[_v2]);puts("");

using namespace std;

typedef long long ll;

typedef unsigned long long ull;

typedef vector vi;

ll read()

const int n=100005*2;

int n,m,k;

vector e[n],t[n];

ll ans=0;

int dfn[n],low[n],st[n],time=0,top=0;

void add_edge(int x,int y)

int size;

void tarjan(int x) while (st[top--]!=y);

}} else

low[x]=min(low[x],dfn[y]);

}int size[n],d[n];

void dfs(int x,int pre)

ans+=2ll*v*size[x]*(size-size[x]);

}int main()

for(i,1,n)

if (!dfn[i])

size=0,tarjan(i),dfs(i,0);

cout

}

APIO2018 鐵人兩項

題意 在乙個無向圖裡面選三個點 s c f 需要能夠從 s 出發,經過 c 到達 f 點,中間不能提前經過 f 且需要是乙個簡單路徑 solution 簡單路徑當然就是園方樹了,想想怎麼統計答案 yy一下可以發現,有一條路徑 s f 中間能選的點就是路徑上的圓點和 因為在乙個點雙連通分量裡面,一定有...

APIO2018 Duathlon 鐵人兩項

給出一張無向圖,問有多少組點a,b,c滿足存在至少一條從a經過b到c的簡單路徑。首先考慮列舉點a,c,這樣每一組a,c對答案的貢獻就是可能在ac路徑之間出現的點的個數,然後我們可以對圖建圓方樹,使圓點的點權為 1 去重 方點的點權為點雙的大小,這樣ac路徑之間出現的點的個數就是a,c兩點在圓方樹上的...

APIO2018 Duathlon 鐵人兩項

不經過重點,考慮點雙 點雙,考慮圓方樹 兩個點s,t,中間路徑上,所有點雙里的點都可以經過,特別地,s,t作為割點的時候,不能往後走,也就是不能經過身後的方點 也就是,s,t 經過樹上路徑上的所有圓點和方點 把方點權值設為點雙大小 2,圓點權值設為1,s,t 路徑上的權值就是c的選擇方案數 不算s,...