前置知識:乙個聯通圖沒有有偶環=它是環套樹或者樹=仙人掌=沒有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時表示對應編號...