【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;
}

猜你喜欢

转载自www.cnblogs.com/ivorysi/p/9080917.html