給定一張 \(n\) 個點 \(m\) 條邊的無向聯通圖,共有 \(q\) 次操作,每次操作選擇一些點作為關鍵點,詢問有多少個點滿足刪去該點及與其相鄰的邊後,至少有兩個關鍵點不能互相到達。\(n,q\leq 10^5,m\leq 2\cdot 10^5,\sum|s|\leq 2\cdot 10^5\)。
還是挺簡單的。
就是圓方樹+虛樹\(\mathrm\)。
但是讓我們看到了未來毒瘤的方向,出題人已經開始把樹上問題放到圖上了。
先把圓方樹建出來,觀察到兩點之間的必經點就是圓方樹上兩點之間路徑的圓點個數。
那就可以虛樹\(\mathrm\)了,記錄 \(dep[x]\) 表示從根到 \(x\) 有多少點是圓點,對於虛樹上的每條邊 \((x,y)\) 計算一下 \(dep[fa[y]]-dep[x]\) 就是這條邊上圓點的貢獻。然後再考慮在虛樹上的點怎麼計算,對於點 \(x\),如果 \(x\) 超過兩個子樹有關鍵點,或者 \(x\) 子樹外還有關鍵點,那麼 \(x\) 一定是必經點,隨便判一下就好了。
然後調了乙個小時的原因是倍增的 \(lg\) 陣列只預處理到了 \(n\),但是建成圓方樹之後深度有可能比 \(n\) 大。
#pragma gcc optimize(2)
#includeusing namespace std;
typedef double db;
typedef long long ll;
const int n=8e5+5;
int lg[n],d[n],f[n][20],ans,len;
int n,m,q,cnt,a[n],sze[n],dfn[n],low[n],head2[n];
int head[n],siz[n],dep[n],sum,stk[n],top,tot,is[n];
struct edgeedge[n<<1],edge2[n<<1];
bool cmp(int x,int y) while(z!=to);
add2(sum,now),add2(now,sum);
}} else low[now]=min(low[now],dfn[to]);
}}void clear()
void dfs(int now,int fa=0)
}int lca(int x,int y)
void ins(int x)
void dfs2(int now) if((siz[now]1) and now<=n and is[now]!=q) ans++;
}void work()
void solve()
signed main()
SDOI2018 戰略遊戲
題目 圓方樹其實並沒有那麼難 圓方樹的構建比較簡單,就是乙個tarjan把點雙跑出來,對於每乙個點雙我們多建乙個方點,把原圖中的點稱為圓點,將點雙內所有圓點向方點連邊,之後我們就得到了原圖的圓方樹 關於圓方樹的性質,zyb大爺在他的題解裡寫了很多,這裡就不再抄一遍了 至於這道題,就是把圓點拿出來建棵...
SDOI2018 戰略遊戲
time limit 30 sec memory limit 512 mb submit 12 solved 9 submit status discuss 省選臨近,放飛自我的小q無心刷題,於是慫恿小c和他一起頹廢,玩起了一款戰略遊戲。這款戰略遊戲的地圖由n個城市以及m條連線這些城市的雙向道路構成...
解題 SDOI2018 戰略遊戲
題面 先圓方樹然後建虛樹,答案就是虛樹大小。虛樹沒必要建出來,把原來的點的點權設為1,直接dfs序排序後相鄰點求距離加上首尾兩個點的距離,最後除以二 畫一下可以發現是正反算了兩遍 注意還要去掉詢問點和補上首尾兩個點的lca 1 include2 include3 include4 include5 ...