Noip模擬賽 C(一道環套樹的神奇題目)

2021-09-26 00:09:30 字數 1413 閱讀 1881

前置知識:乙個聯通圖沒有有偶環=它是環套樹或者樹=仙人掌=沒有2個環共用相鄰的邊(over)

為啥呢:因為若是2個環有相鄰的邊,那麼就存在乙個大環的邊數=奇+奇-2*重複的邊,顯然這是乙個偶數(over)

環套樹的一些性質:m=n(自己想去)所以對於乙個奇環森林就可以做到每個點配對乙個邊。

好,現在考慮題目問的東西。求x,y之間的簡單路徑。而對於x,y來說,只要經過乙個環,他們之間的簡單路徑總是就*2(自己想)

而在樹上的時候顯然2個點之間的最短路徑只有一條。

所以我們要求的東西就是這2個點之間有多少環。

這裡介紹乙個神奇的演算法(只有在環套樹的時候能用啊)

我們要構建乙個方圓樹,圓點就是正常的點。方點是我們把乙個環上所有的點都連在乙個新建的點上。所以我們要找到就是方點的個數。(其實這是乙個類似縮點的過程,noip2018day2 t1旅行 也可以這樣寫,它是乙個簡化的環套樹,不過沒必要。。。)

無向圖縮點我也懶得講了。。。自己想去。。。(參見tarjan演算法)

現在找環=找方點。考慮lca,用w陣列存一下每個點到根的方點的個數。再用lca回答一下詢問,做一下2的次冪,over。

#include using namespace std;

/*這裡是乙個環套樹

*/const int maxn=200005;

const int mo=19491001;

int n,m,q,head[maxn],nxt[maxn],v[maxn],w[maxn];//表示根到他有幾個方點

int dfn[maxn],low[maxn],pa[maxn],vis[maxn],d[maxn],f[maxn][31];

vectorq[maxn];

int indexs=0;int n=0;

void add_edge(int x,int y)

void tarjan(int x)

else low[x]=min(low[x],dfn[v[i]]);

} for(int i=head[x];i!=-1;i=nxt[i])

int main()

tarjan(1);

memset(head,-1,sizeof(head));n=0;

for(int i=1;i<=n;i++)

for(int j=0;jif(vis[q[i][j]]!=i)

/*1-n的q中存的應該是能幫助i走到祖先的點q[i][j]

這個地方已經構造成一棵樹了 (圓方樹)

i與q[i][j]相連(其實上面已經做過了這裡只是判重而已)

*/ dfs(1,0);

for(int i=d[0]=1;i<=n;i++) d[i]=2*d[i-1]%mo;

while(q--)

return 0;

}

一道模擬賽的題

這是乙個不錯的題啊,在這裡記錄一下 聽說不是原創題,那我就放上來了。應該沒有關係吧qaq 有乙個 n m 的地圖,地圖上的每乙個位置可以是空地,炮塔或是敵人.你需要操縱炮塔消滅敵人.對於每個炮塔都有乙個它可以瞄準的方向,你需要在它的瞄準方向上確定乙個它的攻擊位置,當然也可以不進行攻擊.一旦乙個位置被...

NOIP模擬賽 一道挖掉背景的數學題

time limit 1000 ms memory limit 131072 kbytes 給定n與p,求 left lfloor x n right rfloor p x frac 1 輸入一行,兩個非負整數n,p。輸出乙個整數,表示答案 5 97 今天寫道數學題吧owo 這道題我們看到 frac...

每日一道演算法題 約瑟夫環 c 實現

問題描述 n個人坐成乙個圓環 編號為1 n 從第1個人開始報數,數到k的人出列,後面的人重新從1開始報數。問最後剩下的人的編號。例如 n 3,k 2。2號先出列,然後是1號,最後剩下的是3號。最直接的方法是暴力列舉法,第一乙個標誌陣列label n 初始化為0,當label i 等於1時表示對應編號...