제출 #102479

#제출 시각아이디문제언어결과실행 시간메모리
102479Dat160601Cats or Dogs (JOI18_catdog)C++17
100 / 100
441 ms31864 KiB
#include "catdog.h"
#include <bits/stdc++.h>
using namespace std;

#define mp make_pair
#define pb push_back
#define fi first
#define se second

const int N = 1e5 + 7, inf = 1e6;

int n, par[N], head[N], chain[N], pos[N], sz[N], st[N];
vector <int> edge[N];

struct node{
	int dp[2][2];
	node(){
		dp[0][0] = dp[1][1] = 0;
		dp[0][1] = dp[1][0] = inf;
	}
};

node merge(node a, node b){
	node ret;
	for(int i = 0; i <= 1; i++){
		for(int j = 0; j <= 1; j++){
			ret.dp[i][j] = inf;
			for(int k = 0; k <= 1; k++){
				for(int l = 0; l <= 1; l++){
					ret.dp[i][j] = min(ret.dp[i][j], a.dp[i][k] + b.dp[l][j] + (k ^ l));
				}
			}
		}
	}
	return ret;
}

struct segtree{
	vector <node> it;
	int sz;

	void init(int k, int l, int r){
		if(l == r) return;
		int mid = (l + r) >> 1;
		init(k << 1, l, mid);
		init(k << 1 | 1, mid + 1, r);
		it[k] = merge(it[k << 1], it[k << 1 | 1]);
	}

	void init(int pos){
		sz = pos;
		it.resize(4 * sz + 5);
		init(1, 1, sz);
	}

	void update(int k, int l, int r, int pos, int v0, int v1){
		if(l > pos || r < pos) return;
		if(l == r){
			it[k].dp[0][0] += v0;
			it[k].dp[1][1] += v1;
			return;
		}
		int mid = (l + r) >> 1;
		update(k << 1, l, mid, pos, v0, v1);
		update(k << 1 | 1, mid + 1, r, pos, v0, v1);
		it[k] = merge(it[k << 1], it[k << 1 | 1]);
	}

	void update(int pos, int v0, int v1){
		update(1, 1, sz, pos, v0, v1);
	}

	pair <int, int> get(){
		int f1 = min(it[1].dp[0][0], it[1].dp[0][1]);
		int f2 = min(it[1].dp[1][0], it[1].dp[1][1]);
		return mp(min(f1, f2 + 1), min(f1 + 1, f2));
	}
} tree[N];

void dfs(int u, int p){
	sz[u] = 1;
	for(int v : edge[u]){
		if(v == p) continue;
		par[v] = u;
		dfs(v, u);
		sz[u] += sz[v];
	}
}

void hld(int u, int p){
	int nxt = -1;
	for(int v : edge[u]){
		if(v == p) continue;
		if(nxt < 0 || sz[nxt] < sz[v]){
			nxt = v;
		}
	}
	if(nxt < 0){
		tree[chain[u]].init(pos[u]);
		return;
	}
	chain[nxt] = chain[u];
	pos[nxt] = pos[u] + 1;
	hld(nxt, u);
	for(int v : edge[u]){
		if(v == p || v == nxt) continue;
		chain[v] = v;
		head[v] = v;
		pos[v] = 1;
		hld(v, u);
	}
}

void initialize(int p, vector <int> A, vector <int> B){
	n = p;
	for(int i = 0; i < n - 1; i++){
		edge[A[i]].pb(B[i]);
		edge[B[i]].pb(A[i]);
	}
	dfs(1, 1);
	head[1] = 1, chain[1] = 1, pos[1] = 1;
	hld(1, 1);
}

void solve(int u, int v0, int v1){
	while(u){
		int cur = chain[u];
		//cout << cur << endl;
		int pv0, pv1;
		pair <int, int> now = tree[cur].get();
		pv0 = now.fi, pv1 = now.se;
		tree[cur].update(pos[u], v0, v1);
		now = tree[cur].get();
		v0 = now.fi - pv0, v1 = now.se - pv1;
		u = head[cur];
		u = par[u];
	}
}

int getans(){
	return min(min(tree[1].it[1].dp[0][0], tree[1].it[1].dp[0][1]), min(tree[1].it[1].dp[1][0], tree[1].it[1].dp[1][1]));
}

int cat(int v) {
	st[v] = 1;
	solve(v, 0, inf);
	return getans();
}

int dog(int v) {
	st[v] = 2;
	solve(v, inf, 0);
	return getans();
}

int neighbor(int v){
	if(st[v] == 0) return getans();
	if(st[v] == 1) solve(v, 0, -inf);
	if(st[v] == 2) solve(v, -inf, 0);
	st[v] = 0;
	return getans();
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...