當前位置:
首頁 >
【SDOI2018】战略游戏【圆方树】【虚树】
發布時間:2023/12/3
40
豆豆
生活随笔
收集整理的這篇文章主要介紹了
【SDOI2018】战略游戏【圆方树】【虚树】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:給一張 nnn 點 mmm 邊的連通無向圖,qqq 次詢問,每次給出一個點集 SSS ,求有多少個不在 SSS 中的點滿足刪除后 SSS 中存在兩個點不連通。
n≤105,m≤2×105,∑∣S∣≤2×105n\leq 10^5,m\leq 2\times 10^5,\sum |S|\leq 2\times 10^5n≤105,m≤2×105,∑∣S∣≤2×105
顯然是虛樹
題目相當于求 SSS 的割點數量,想到圓方樹
建出圓方樹后,對于 SSS 中的一對點,它們路徑上任意一個圓點都滿足條件。答案相當于求兩兩路徑上的圓點的并集。因為不能取 SSS 中的點,所以要減去 ∣S∣|S|∣S∣。
套到虛樹上,發現就是虛樹覆蓋的圓點個數。即對于每個點 uuu ,設 faufa_ufau? 為其虛樹上的父親,sumusum_usumu? 為原樹上根到 uuu 的圓點個數。那么答案為 ∑(sumu?sumfau)\sum(sum_u-sum_{fa_u})∑(sumu??sumfau??)。
注意要特判 lca?(S)\operatorname{lca}(S)lca(S)
復雜度 O(n+m+∑∣S∣log?∣S∣)O(n+m+\sum|S|\log |S|)O(n+m+∑∣S∣log∣S∣)
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <vector> #include <algorithm> #define MAXN 400005 #define MAXM 800005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } struct edge{int u,v;}e[MAXM]; int head[MAXN],nxt[MAXM],cnt; inline void addnode(int u,int v) {e[++cnt]=(edge){u,v};nxt[cnt]=head[u];head[u]=cnt; } int n,m; int dfn[MAXN],low[MAXN],tim; int stk[MAXN],tp,vis[MAXN],bcc[MAXN],vcnt; vector<int> rtt[MAXN]; void tarjan(int u) {dfn[u]=low[u]=++tim;for (int i=head[u];i;i=nxt[i]){if (!vis[i>>1]&&!bcc[i>>1]) vis[(stk[++tp]=i)>>1]=1;if (!dfn[e[i].v]){tarjan(e[i].v);low[u]=min(low[u],low[e[i].v]);if (dfn[u]==low[e[i].v]){rtt[u].push_back(bcc[i>>1]=++vcnt);rtt[bcc[i>>1]].push_back(u);while (vis[i>>1]){int t=stk[tp--];vis[t>>1]=0;rtt[bcc[t>>1]=vcnt].push_back(e[t].v);}}}else low[u]=min(low[u],dfn[e[i].v]);} } int sum[MAXN],dep[MAXN],fa[MAXN][20]; void dfs(int u) {dfn[u]=++tim;for (int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];for (int i=0;i<(int)rtt[u].size();i++)if (!dep[rtt[u][i]]){dep[rtt[u][i]]=dep[u]+1;sum[rtt[u][i]]=sum[u]+(rtt[u][i]<=n);fa[rtt[u][i]][0]=u;dfs(rtt[u][i]); } } inline int lca(int x,int y) {if (dep[x]<dep[y]) swap(x,y);int t=dep[x]-dep[y];for (int i=0;(1<<i)<=t;i++) if (t&(1<<i)) x=fa[x][i];if (x==y) return x;for (int i=19;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];return fa[x][0]; } int lis[MAXM],len; inline bool cmp(const int& x,const int& y){return dfn[x]<dfn[y];} inline void solve() {sort(lis+1,lis+len+1,cmp);int res=len;for (int i=1;i<res;i++) lis[++len]=lca(lis[i],lis[i+1]);sort(lis+1,lis+len+1,cmp);len=unique(lis+1,lis+len+1)-lis-1;int ans=0;tp=0;for (int i=1;i<=len;i++){while (tp&&lca(stk[tp],lis[i])!=stk[tp]) --tp;ans+=(tp? sum[lis[i]]-sum[stk[tp]]:(lis[i]<=n));stk[++tp]=lis[i];}printf("%d\n",ans-res); } int main() {for (int T=read();T;T--){n=read(),m=read();cnt=1;memset(head,0,sizeof(head));memset(nxt,0,sizeof(nxt));memset(bcc,0,sizeof(bcc));memset(dep,0,sizeof(dep));memset(sum,0,sizeof(sum));memset(dfn,0,sizeof(dfn));for (int i=1;i<=vcnt;i++) rtt[i].clear();tim=tp=0;for (int i=1;i<=m;i++){int u,v;u=read(),v=read();addnode(u,v),addnode(v,u);}vcnt=n;tarjan(1);for (int i=n+1;i<=vcnt;i++) {sort(rtt[i].begin(),rtt[i].end());rtt[i].erase(unique(rtt[i].begin(),rtt[i].end()),rtt[i].end());}dep[1]=sum[1]=1,tim=0;dfs(1);for (int q=read();q;q--){len=read();for (int i=1;i<=len;i++) lis[i]=read();solve();}}return 0; }總結
以上是生活随笔為你收集整理的【SDOI2018】战略游戏【圆方树】【虚树】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 凤凰男的八大特征 什么是凤凰男
- 下一篇: 怎么使用织梦模板(怎么使用织梦模板做手帐