毒瘤仙人掌,明明放到樹上一道板題的非要構造到仙人掌上來出題orz orz orz orz orz
在oi的上古時代,流傳著這樣乙個故事:
有一天,小w到森林裡遊玩,回來之後跟小v說,我發現好多棵會動的樹耶!小v說,這有什麼好稀奇的,我用手指頭就能維護每棵樹的形態。
於是又過了幾天小w到沙漠裡遊玩,回來之後跟小v說,我發現好多棵會動的仙人掌耶!小v說,這有什麼好稀奇的,我用腳丫子就能維護每棵仙人掌的形態。
小s看到了這段故事,深受感動。他決定一步步做起,從仙人掌做起,從不會動的仙人掌做起。
本題中,我們定義:
如果乙個無向連通圖的任意一條邊最多屬於乙個簡單環,且不存在自環,我們就稱之為仙人掌。
仙人掌上的兩點間最短路徑(一定是簡單路徑)與最長簡單路徑的定義與一般無向圖的定義相同。
本題中,我們還保證任何乙個簡單環的長度均為奇數。這意味著不存在重邊,並且任意兩點間的最短路徑與最長簡單路徑一定是唯一的。
為了證明你確實能夠維護仙人掌,我們給你 $n$ 個結點,從 $1$ 到 $n$ 標號,其中 $1$ 號點是仙人掌的根。它有 $m$ 條邊,第 $i$ 條邊連線了結點 $u_i$ 與 $v_i$。
每個結點有乙個顏色(黑或白),初始時均為黑色。現在有 $q$ 次操作,每次操作格式為 $op$ $x$($1 \leq op \leq 3, 1 \leq x \leq n$):第一行三個用空格隔開的正整數 $n,m,q$ 表示一共有 $n$ 個結點,$m$ 條邊,$q$ 個操作。
接下來 $m$ 行,每行兩個空格隔開的正整數 $u_i, v_i$,表示一條邊。
接下來 $q$ 行,每行表示乙個操作,格式如上述。對於每個 $op=3$ 的操作,輸出一行相應的結果。input
7 9 11output1 21 3
2 33 4
3 54 5
5 65 7
6 73 1
3 23 3
1 73 1
3 23 3
2 73 1
3 23 3
715本題使用**測試。每個子任務有若干個測試點,分為 $8$ 個子任務,你只有通過乙個子任務的所有測試點才能得到這個子任務的分數。3124
03
前七個子任務的限制時間限制:$1\texttt$。空間限制:$768\texttt$。
$n, q \leq 50000$。
子任務1(7分)
$n \leq 2, q \leq 2000$。
子任務2(14分)
$n \leq 20, q \leq 2000$。
子任務3(9分)
$n, q \leq 2000$。
子任務4(17分)
保證 $m=n-1$,並且 $u_i=i,v_i=i+1$,且不存在 $op=2$ 的操作。
子任務5(14分)
保證 $m=n-1$,並且 $u_i < v_i$,且不存在 $op=2$ 的操作。
子任務6(11分)
保證不存在 $op=2$ 的操作。
子任務7(18分)
沒有特殊的限制與約定。
子任務8(10分)
空間限制縮小為 $128\texttt$。
我們發現,如果這只是一棵樹,嘿嘿嘿,那不就是裸的樹剖嗎。
可惜他是乙個仙人掌。
那麼我們就利用圓方樹來進行仙人掌剖分。對於仙人掌的剖分不能按照樹一樣直接剖,考慮到我們可能應該在同乙個環上的點剖在一起。那麼就這樣處理-->我們把所有的點分成三類點:0,在鏈上的點(除了1號點外不包括鏈根)1.在環上並且處於從重兒子到環根最短路徑上 2,在環上並且處於從重兒子到環根的長路徑上。
我們在樹剖的時候,如果遇到圓點繼續剖下去,遇到方點,將環按照環序加入到樹剖序中(在這裡我們都不考慮作為方點父親的那乙個圓點),並且跳過重兒子,之後再進行剖,並且給環上所有點記錄下型別,然後繼續剖。圓點樹剖記得子樹(仙人掌)範圍,方點記錄輕環兒子的範圍。
線段樹維護3種點黑點的和個數,帶lazy下放。
查詢就直接查詢那個點和那個點的子仙人掌。
修改的時候跳一跳,發現top是方點(說明是從方點的重兒子跳過來的),直接修改。如果top是圓點(說明到達top的父親方點的環的輕兒子),稍微特殊處理一下就好了。
code:
#include#include#include#include#includeusing namespace std;
const int maxn = 2e5+5;
/*0 the point on the line
1 the sort point on the cir
2 the long point on the cir
*/struct edge
}v,g;
int n,m,q,scc;
struct dddpos[maxn];
int kind[maxn];
namespace tajanwhile(o!=y);
g.adg(x,scc);
}} else low[x] = min(low[x],dfn[y]);}}
}int top[maxn],siz[maxn],dis[maxn],zerz[maxn],id[maxn],dy[maxn],tot,fa[maxn];
void dfsgsz(int x,int ba)
}void dfsgps(int x,int ace)
} else
dis[x]++; kind[x] = 0;
int pp = (dis[zerz[x]] <= (dis[x]>>1) )?1:2;
for(int it=g.la[x];it;it=g.nt[it])
}pos[x].r = tot;
++tot; id[zerz[x]] = tot; kind[zerz[x]] = 0; dy[tot] = zerz[x];
}dfsgps(zerz[x],ace);
for(int it=g.la[x];it;it=g.nt[it])
if(x<=n) pos[x].r = tot;
}namespace segz[maxn],*rt; int tot;
void chan(node *&p,int c)
void ptd(node *&p) }}
void upd(node *&p)
}void maketree(node *&p,int l,int r)
return;
}int mid = (l+r)>>1;
maketree(p->ls,l,mid); maketree(p->rs,mid+1,r);
upd(p);
for(int i=0;i<=2;i++) p->pt[i] = p->ls->pt[i] + p->rs->pt[i];
}void changeall(node *&p,int l,int r,int x,int y)
ptd(p);
int mid = (l+r)>>1;
if(y<=mid) changeall(p->ls,l,mid,x,y);
else if(x>mid) changeall(p->rs,mid+1,r,x,y);
else changeall(p->ls,l,mid,x,y),changeall(p->rs,mid+1,r,x,y);
upd(p);
}void changekind(node *&p,int l,int r,int x,int y,int cc)
ptd(p);
int mid = (l+r)>>1;
if(y<=mid) changekind(p->ls,l,mid,x,y,cc);
else if(x>mid) changekind(p->rs,mid+1,r,x,y,cc);
else changekind(p->ls,l,mid,x,y,cc),changekind(p->rs,mid+1,r,x,y,cc);
upd(p);
}int getsumall(node *&p,int l,int r,int x,int y)
}void solve(int x,int op) else else }}
seg::changekind(seg::rt,1,scc,id[1],id[x],op);
}int getans(int x)
int main()
tajan::tarjan(1);
dfsgsz(1,0);
top[1] = id[1] = dy[1] = tot = 1;
dfsgps(1,1);
seg::maketree(seg::rt,1,tot);
for(int i=1;i<=q;i++)
}
靜態仙人掌 模板 tarjan LCA
description 這是一道靜態仙人掌 block forest data structure 的模板題。如果您不知道什麼是仙人掌,那麼此處給出無向仙人掌圖的定義 任意一條邊至多只出現在一條簡單迴路的無向連通圖稱為仙人掌。給你乙個有 n 個點和 m 條邊的仙人掌圖,和 q 組詢問 每次詢問兩個點...
動態仙人掌(dinosaur
分析 這道題在考場看到我是完全的蒙蔽的,驚人的妄想著能否用資料離散化後的dp來騙分。我果然很菜。好吧,對於我這種菜雞來說,正解似乎有些難想,讓我們考慮從最基本的情況開始考慮。先將所有仙人掌按p為第一關鍵字排序,從左向右掃。這裡我們考慮乙個貪心策略,如果仙人掌兩兩之間距離足夠遠,則仙人掌之間跳躍的最小...
題解 仙人掌計數
題目傳送門 給出 q 個查詢,每次查詢 n 個點的無根有標號仙人掌有多少個。q le 5 times 10 4,n 131072 因為這道題太難碼了,所以先把題解寫了再寫 好奇怪啊 終於碼出來了,果然還是 text 好用 霧 為了方便,我們下面的答案其實求的是有根有標號的答案,最後除以 n 就好了。...