SDOI2018 戰略遊戲

2022-06-03 10:12:10 字數 3211 閱讀 5074

time limit: 30 sec  memory limit: 512 mb

submit: 12  solved: 9

[submit][status][discuss]

省選臨近,放飛自我的小q無心刷題,於是慫恿小c和他一起頹廢,玩起了一款戰略遊戲。

這款戰略遊戲的地圖由n個城市以及m條連線這些城市的雙向道路構成,並且從任意乙個城市出發總能沿著道路走到

任意其他城市。現在小c已經占領了其中至少兩個城市,小q可以摧毀乙個小c沒占領的城市,同時摧毀所有連線這

個城市的道路。只要在摧毀這個城市之後能夠找到某兩個小c占領的城市u和v,使得從u出發沿著道路無論如何都不

能走到v,那麼小q就能贏下這一局遊戲。

小q和小c一共進行了q局遊戲,每一局遊戲會給出小c占領的城市集合s

你需要幫小q數出有多少個城市在他摧毀之後能夠讓他贏下這一局遊戲。

第一行包含乙個正整數t,表示測試資料的組數,

對於每組測試資料,

第一行是兩個整數n和m,表示地圖的城市數和道路數,

接下來m行,每行包含兩個整數u和v~(1<=u表示第u個城市和第v個城市之間有一條道路,同一對城市之間可能有多條道路連線,

第m+1是乙個整數q,表示遊戲的局數,

接下來q行,每行先給出乙個整數|s|(2<=|s|<=n)

表示小c占領的城市數量,然後給出|s|個整數s1,s2,...s|s|,(1<=s11<= t<= 10,

2<= n<= 10^5 且 n-1<= m<= 2*10^5,

1<= q<= 10^5,

對於每組測試資料,有sigma|s|<= 2*10^5

對於每一局遊戲,輸出一行,包含乙個整數,表示這一局遊戲中有多少個城市在小q摧毀之後能夠讓他贏下這一局遊戲。

7 61 2

1 32 4

2 53 6

3 73

2 1 2

3 2 3 4

4 4 5 6 7

6 61 2

1 32 3

1 42 5

3 64

3 1 2 3

3 1 2 6

3 1 5 6

3 4 5 601

3012

3考場上想出來發現是個圓方樹。。。但是以前沒寫過怎麼辦啊qwq

不管了,硬鋼吧23333

(然後最後就神奇的鋼出來了)

#include#include#include#include#include#include#include#include#include#include#define ll long long

#define pb push_back

#define mid (l+r>>1)

#define lc (o<<1)

#define rc ((o<<1)|1)

using namespace std;

using namespace std::tr1;

const int maxn=400005;

vectorg[maxn];

unordered_mapmmp[maxn];

int t,n,m,num,hd[maxn],to[maxn*2],ne[maxn*2];

int dfn[maxn],low[maxn],dc,cnt,rp[maxn],dy[maxn],dep[maxn];

int siz[maxn],son[maxn],cl[maxn],f[maxn],l,q,now[maxn],k,ans;

int lim[maxn*4],sum[maxn*4],le,ri,w,tag[maxn*4];

struct lines;

stacks;

inline int read()

void wt(int x) if(x>=10) wt(x/10); putchar(x%10+'0');}

inline void add(int x,int y)

inline void add(int x,int y)

inline void init()

void dfs(int x,int fa);

if(!dfn[to[i]])}}

else if(dfn[to[i]]=0;i--)}

void build(int o,int l,int r)

build(lc,l,mid),build(rc,mid+1,r);

lim[o]=lim[lc]+lim[rc];}

inline void work1(int o)

inline void work2(int o)

inline void pushdown(int o)

else if(tag[o])

tag[o]=0;}

inline void maintain(int o)

void update1(int o,int l,int r)

pushdown(o);

if(le<=mid) update1(lc,l,mid);

if(ri>mid) update1(rc,mid+1,r);

maintain(o);}

void update2(int o,int l,int r)

pushdown(o);

if(le<=mid) update2(lc,l,mid);

if(ri>mid) update2(rc,mid+1,r);

maintain(o);}

inline int lca(int x,int y)

return dep[x]>dep[y]?y:x;}

inline void paint(int x)}

inline void rev(int x) }

inline void solve()

*/memset(dfn,0,sizeof(dfn)),dc=0;

rp[1]=1,dfs1(1,0),dfs2(1,1);

build(1,1,cnt);

q=read();

while(q--)

wt(ans-rp[f[l]]-k),puts("");

for(int i=1;i<=k;i++) rev(now[i]);

}} int main()

for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i,-1);

solve();

}return 0;

}

SDOI2018 戰略遊戲

給定一張 n 個點 m 條邊的無向聯通圖,共有 q 次操作,每次操作選擇一些點作為關鍵點,詢問有多少個點滿足刪去該點及與其相鄰的邊後,至少有兩個關鍵點不能互相到達。n,q leq 10 5,m leq 2 cdot 10 5,sum s leq 2 cdot 10 5 還是挺簡單的。就是圓方樹 虛樹...

SDOI2018 戰略遊戲

題目 圓方樹其實並沒有那麼難 圓方樹的構建比較簡單,就是乙個tarjan把點雙跑出來,對於每乙個點雙我們多建乙個方點,把原圖中的點稱為圓點,將點雙內所有圓點向方點連邊,之後我們就得到了原圖的圓方樹 關於圓方樹的性質,zyb大爺在他的題解裡寫了很多,這裡就不再抄一遍了 至於這道題,就是把圓點拿出來建棵...

解題 SDOI2018 戰略遊戲

題面 先圓方樹然後建虛樹,答案就是虛樹大小。虛樹沒必要建出來,把原來的點的點權設為1,直接dfs序排序後相鄰點求距離加上首尾兩個點的距離,最後除以二 畫一下可以發現是正反算了兩遍 注意還要去掉詢問點和補上首尾兩個點的lca 1 include2 include3 include4 include5 ...