【LOJ】#2562. 「SDOI2018」战略游戏
题解
圆方树建好之后点是原来的两倍,而st表求lca也要开到点的两倍,所以是四倍
我并没有开小,然而= =,我的预处理log2,写成了200000,而不是400000
我是不是折翼啊= =
很可写,我们对于割点考虑一下圆方树,发现答案就是圆方树上两个圆点之间经过了多少圆点,把圆点拿出来然后建立虚树,统计一下这个点和父亲之间有多少个圆点,建立虚树之后统计一下加入的lca是不是圆点,如果是的话也要把答案+1
代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
//#define ivorysi
#define pb push_back
#define MAXN 200005
#define eps 1e-12
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define fi first
#define se second
#define mo 974711
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 - '0' + c;
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) putchar('-'),x = -x;
while(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int T;
int N,M,Q,sumE,head[MAXN],Cnt;
struct node {
int to,next;
}E[MAXN * 4];
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
int dfn[MAXN],low[MAXN],idx,sta[MAXN],top,st[MAXN * 2][20],dep[MAXN],cir[MAXN],len[MAXN * 2];
vector<int> ver[MAXN];
int MK[MAXN],C,ans;
void Tarjan(int u,int fa) {
dfn[u] = low[u] = ++idx;
sta[++top] = u;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(dfn[v] && v != fa) {
low[u] = min(dfn[v],low[u]);
}
else if(v != fa){
Tarjan(v,u);
if(low[v] >= dfn[u]) {
++Cnt;
ver[u].pb(Cnt);
while(1) {
int x = sta[top--];
ver[Cnt].pb(x);
if(x == v) break;
}
}
else low[u] = min(low[u],low[v]);
}
}
}
int min_dep(int a,int b) {
return dep[a] < dep[b] ? a : b;
}
int lca(int u,int v) {
u = dfn[u],v = dfn[v];
if(u > v) swap(u,v);
int l = len[v - u + 1];
return min_dep(st[u][l],st[v - (1 << l) + 1][l]);
}
void dfs(int u,int fa) {
dfn[u] = ++idx;
st[idx][0] = u;
cir[u] = cir[fa];
dep[u] = dep[fa] + 1;
if(u <= N) ++cir[u];
for(auto k : ver[u]) {
dfs(k,u);
st[++idx][0] = u;
}
}
bool cmp(int a,int b) {
return dfn[a] < dfn[b];
}
int calc(int a,int b) {
if(dep[a] < dep[b]) swap(a,b);
return cir[a] - cir[b] - (a <= N);
}
void Build_aux() {
sort(MK + 1,MK + C + 1,cmp);
top = 0;
for(int i = 1 ; i <= C ; ++i) {
if(!top) sta[++top] = MK[i];
else {
int l = lca(sta[top],MK[i]);
while(top && dep[sta[top]] > dep[l]) {
if(top == 1 || dep[sta[top - 1]] <= dep[l]) {
ans += calc(sta[top],l);
}
else {
ans += calc(sta[top],sta[top - 1]);
}
--top;
}
if(sta[top] != l) {
if(l <= N) ++ans;
sta[++top] = l;
}
sta[++top] = MK[i];
}
}
for(int i = top ; i >= 2 ; --i) ans += calc(sta[i],sta[i - 1]);
}
void Init() {
read(N);read(M);
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(head,0,sizeof(head));
idx = 0;top = 0;sumE = 0;
for(int i = 1 ; i <= 2 * N ; ++i) ver[i].clear();
Cnt = N;
int u,v;
for(int i = 1 ; i <= M ; ++i) {
read(u);read(v);add(u,v);add(v,u);
}
Tarjan(1,0);
idx = 0;
dfs(1,0);
for(int j = 1 ; j <= 19 ; ++j) {
for(int i = 1 ; i <= idx; ++i) {
if(i + (1 << j) - 1 > idx) break;
st[i][j] = min_dep(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
}
}
}
void Solve() {
read(Q);
while(Q--) {
read(C);
for(int i = 1 ; i <= C ; ++i) read(MK[i]);
ans = 0;
Build_aux();
printf("%d\n",ans);
}
}
int main() {
#ifdef ivorysi
freopen("01.in","r",stdin);
#endif
for(int i = 2 ; i <= 400000 ; ++i) len[i] = len[i / 2] + 1;
read(T);
while(T--) {
Init();
Solve();
}
return 0;
}