제출 #390119

#제출 시각아이디문제언어결과실행 시간메모리
390119maximath_1Cats or Dogs (JOI18_catdog)C++11
100 / 100
919 ms42052 KiB
#include "catdog.h" #include <vector> #include <algorithm> using namespace std; const int MX = 200005; const int inf = 1000000069; int n, a[MX], b[MX]; vector<int> adj[MX]; int sz[MX], depth[MX], head[MX], in[MX], cnt[MX], par[MX], tim = 0; void dfs_sz(int nw, int bf = -1){ sz[nw] = 1; par[nw] = bf; for(int &nx : adj[nw]){ depth[nx] = depth[nw] + 1; adj[nx].erase(find(adj[nx].begin(), adj[nx].end(), nw)); dfs_sz(nx, nw); sz[nw] += sz[nx]; if(sz[nx] > sz[adj[nw][0]]) swap(nx, adj[nw][0]); } } void dfs_hld(int nw){ in[nw] = tim ++; cnt[head[nw]] ++; for(int nx : adj[nw]){ head[nx] = (nx == adj[nw][0] ? head[nw] : nx); dfs_hld(nx); } } void init_hld(int root = 0){ par[root] = depth[root] = tim = 0; dfs_sz(root); head[root] = root; dfs_hld(root); } struct dat{ int dp[2][2]; dat(){dp[0][0] = dp[0][1] = dp[1][0] = dp[1][1] = inf;} dat(int s0, int s1, int tp){ dp[0][0] = dp[0][1] = dp[1][0] = dp[1][1] = inf; if(tp != 2) dp[0][0] = s0; if(tp != 1) dp[1][1] = s1; } }; dat merge(dat lf, dat rg){ dat rs = dat(); for(int pl = 0; pl < 2; pl ++) for(int ql = 0; ql < 2; ql ++) if(lf.dp[pl][ql] != inf){ for(int pr = 0; pr < 2; pr ++) for(int qr = 0; qr < 2; qr ++) if(rg.dp[pr][qr] != inf){ rs.dp[pl][qr] = min(rs.dp[pl][qr], lf.dp[pl][ql] + (ql ^ pr) + rg.dp[pr][qr]); } } return rs; } dat st[MX * 4]; void build_tree(int nd, int cl, int cr){ if(cl == cr) return void(st[nd] = dat(0, 0, 0)); build_tree(nd * 2, cl, (cl + cr) / 2); build_tree(nd * 2 + 1, (cl + cr) / 2 + 1, cr); st[nd] = merge(st[nd * 2], st[nd * 2 + 1]); } void upd_tree(int nd, int cl, int cr, int ps, int s0, int s1, int tp){ if(ps < cl || cr < ps) return; if(cl == cr) return void(st[nd] = dat(s0, s1, tp)); upd_tree(nd * 2, cl, (cl + cr) / 2, ps, s0, s1, tp); upd_tree(nd * 2 + 1, (cl + cr) / 2 + 1, cr, ps, s0, s1, tp); st[nd] = merge(st[nd * 2], st[nd * 2 + 1]); } dat que_tree(int nd, int cl, int cr, int lf, int rg){ if(lf <= cl && cr <= rg) return st[nd]; if(rg <= (cl + cr) / 2) return que_tree(nd * 2, cl, (cl + cr) / 2, lf, rg); if((cl + cr) / 2 < lf) return que_tree(nd * 2 + 1, (cl + cr) / 2 + 1, cr, lf, rg); return merge( que_tree(nd * 2, cl, (cl + cr) / 2, lf, rg), que_tree(nd * 2 + 1, (cl + cr) / 2 + 1, cr, lf, rg) ); } int tp[MX], s0[MX], s1[MX]; dat get_dp(int x){ return que_tree(1, 0, n - 1, in[x], in[head[x]] + cnt[head[x]] - 1); } void upd_ac(int x){ upd_tree(1, 0, n - 1, in[x], s0[x], s1[x], tp[x]); } int get_ans(){ dat r1 = get_dp(0); int ans = inf; for(int i = 0; i < 2; i ++) for(int j = 0; j < 2; j ++) ans = min(ans, r1.dp[i][j]); return ans; } void change_type(int nw, int t){ for(int cr = nw; cr != -1;){ if(cr == head[cr]){ if(par[cr] == -1) break; dat cur = get_dp(cr); int dp0 = min(cur.dp[0][0], cur.dp[0][1]); int dp1 = min(cur.dp[1][0], cur.dp[1][1]); s0[par[cr]] -= min(dp0, dp1 + 1); s1[par[cr]] -= min(dp1, dp0 + 1); cr = par[cr]; }else cr = head[cr]; } tp[nw] = t; upd_ac(nw); for(int cr = nw; cr != -1;){ if(cr == head[cr]){ if(par[cr] == -1) break; dat cur = get_dp(cr); int dp0 = min(cur.dp[0][0], cur.dp[0][1]); int dp1 = min(cur.dp[1][0], cur.dp[1][1]); s0[par[cr]] += min(dp0, dp1 + 1); s1[par[cr]] += min(dp1, dp0 + 1); upd_ac(par[cr]); cr = par[cr]; }else cr = head[cr]; } } void init(){ for(int i = 0; i < MX; i ++){ adj[i].clear(); sz[i] = depth[i] = head[i] = in[i] = cnt[i] = par[i] = tp[i] = s1[i] = s0[i] = 0; } for(int i = 0; i < n - 1; i ++){ adj[a[i]].push_back(b[i]); adj[b[i]].push_back(a[i]); } init_hld(); build_tree(1, 0, n - 1); } void initialize(int _n, vector<int> _a, vector<int> _b){ n = _n; for(int i = 0; i < n - 1; i ++) a[i] = _a[i] - 1, b[i] = _b[i] - 1; init(); } int cat(int v){ change_type(v - 1, 1); return get_ans(); } int dog(int v){ change_type(v - 1, 2); return get_ans(); } int neighbor(int v){ change_type(v - 1, 0); return get_ans(); }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...