4316: 小C的独立集
思路:先将树上的转移做好。然后环上的转移就是强制最上面的的点选或者不选,然后在环上跑一遍转移就可以了。
代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define y1 y11 #define fi first #define se second #define pi acos(-1.0) #define LL long long //#define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pli pair<LL, int> #define pii pair<int, int> #define piii pair<pii, int> #define pdd pair<double, double> #define mem(a, b) memset(a, b, sizeof(a)) #define debug(x) cerr << #x << " = " << x << "\n"; #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); //head const int N = 6e4 + 10; vector<int> g[N]; int n, m, u, v, dp[N][2], fa[N]; int low[N], dfn[N], stk[N], cmp[N], cnt = 0, top = 0, tot = 0; bool vis[N]; inline void DP(int u, int v) { int now0 = 0, now1 = 0; for (int i = v; i != u; i = fa[i]) { int t0 = now0 + dp[i][0]; int t1 = now1 + dp[i][1]; now0 = max(t0, t1); now1 = t0; } dp[u][0] += now0; now0 = 0, now1 = -10000000; for (int i = v; i != u; i = fa[i]) { int t0 = now0 + dp[i][0]; int t1 = now1 + dp[i][1]; now0 = max(t0, t1); now1 = t0; } dp[u][1] += now1; } inline void tarjan(int u) { low[u] = dfn[u] = ++cnt; stk[++top] = u; vis[u] = true; //标记是否在栈中 dp[u][1] = 1; for (int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(!dfn[v]) { fa[v] = u; tarjan(v); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], dfn[v]); if(low[v] > dfn[u]) { dp[u][0] += max(dp[v][0], dp[v][1]); dp[u][1] += dp[v][0]; } } for (int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(fa[v] != u && dfn[v] > dfn[u]) { DP(u, v); } } } int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= m; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u); tarjan(1); printf("%d\n", max(dp[1][0], dp[1][1])); return 0; }