Submission #148110

#TimeUsernameProblemLanguageResultExecution timeMemory
148110WhipppedCreamValley (BOI19_valley)C++17
100 / 100
1203 ms107572 KiB
#include <bits/stdc++.h>
#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")
using namespace std;
#define X first
#define Y second
#define pb push_back
typedef pair<int, int> ii;
typedef long long ll;

const int maxn = 1e5+5;

int n, k, q, e;

int len[maxn];
vector< ii > way[maxn];
vector< ii > adj[maxn];
int mp[maxn];
int sigan = 0;

struct node
{
	int key, pr;
	ll val, opt;
	node *left, *right;
	node(int key, ll val) : key(key), val(val)
	{
		opt = val;
		pr = (rand()<<16)^rand();
		left = right = NULL;
	}
	void calc()
	{
		opt = val;
		if(left) opt = min(left->opt, opt);
		if(right) opt = min(right->opt, opt);
	}
};

typedef node* ps;

ps merge(ps L, ps R)
{
	if(!L || !R) return L?L:R;
	if(L->pr> R->pr)
	{
		L->right = merge(L->right, R);
		L->calc();
		return L;
	}
	else
	{
		R->left = merge(L, R->left);
		R->calc();
		return R;
	}
}

pair<ps, ps> split(ps big, int key)
{
	if(!big) return {NULL, NULL};
	int here = big->key;
	if(here<= key)
	{
		auto tmp = split(big->right, key);
		big->right = tmp.X;
		big->calc();
		return {big, tmp.Y};
	}
	else
	{
		auto tmp = split(big->left, key);
		big->left = tmp.Y;
		big->calc();
		return {tmp.X, big};
	}
}

int road[maxn];

void renumb(int u = 1, int p = 0)
{
	sigan++;
	mp[u] = sigan;
	for(auto vv : way[u])
	{
		int v = vv.X, id = vv.Y;
		if(v == p) continue;
		// printf("road[%d] = %d\n", id, v);
		road[id] = v;
		renumb(v, u);
	}
}

int cnt[maxn];
bitset<maxn> ban;

void findcnt(int u, int p)
{
	cnt[u] = 1;
	for(ii vv : adj[u])
	{
		int v = vv.X;
		if(v == p || ban[v]) continue;
		findcnt(v, u);
		cnt[u] += cnt[v];
	}
}

int gimme(int u, int p, int tot)
{
	for(ii vv : adj[u])
	{
		int v = vv.X;
		if(v == p || ban[v]) continue;
		if(2*cnt[v]> tot)
		{
			return gimme(v, u, tot);
		}
	}
	return u;
}

bitset<maxn> isshop;

ps root[maxn];

void solve(int u, int p, int cent, ll cur_dep)
{
	// printf("go %d %lld\n", u, cur_dep);
	if(isshop[u])
	{
		// add (u, cur_dep) to root[cent]
		// printf("beginning to add\n");
		auto tmp = split(root[cent], u);
		// printf("split ok\n");
		ps tmp2 = merge(tmp.X, new node(u, cur_dep));
		root[cent] = merge(tmp2, tmp.Y);
		// printf("add (%d, %lld) to centroid %d\n", u, cur_dep, cent);
	}
	for(ii vv : adj[u])
	{
		int v = vv.X, w = vv.Y;
		if(v == p || ban[v]) continue;
		solve(v, u, cent, cur_dep+len[w]);
	}
}

int par[maxn];

void centroid(int u, int lst)
{
	findcnt(u, 0);
	// printf("kuy\n");
	int tot = cnt[u];
	int cent = gimme(u, 0, tot);
	par[cent] = lst;
	solve(cent, 0, cent, 0);
	ban[cent] = true;
	for(ii vv : adj[cent])
	{
		int v = vv.X;
		if(ban[v]) continue;
		centroid(v, cent);
	}
}

ll from[maxn];
int dep[maxn];
int dp[21][maxn];

void util(int u = 1, int p = 0)
{
	dep[u] = dep[p]+1;
	dp[0][u] = p;
	for(int i = 1; i<= 20; i++) dp[i][u] = dp[i-1][dp[i-1][u]];
	for(ii vv : adj[u])
	{
		int v = vv.X, w = vv.Y;
		if(v == p) continue;
		from[v] = from[u]+len[w];
		util(v, u);
	}
}

int LCA(int u, int v)
{
	if(dep[u]< dep[v]) swap(u, v);
	for(int i = 20; i>= 0; i--)
	{
		int x = dp[i][u];
		if(dep[x]>= dep[v]) u = x;
	}
	if(u == v) return u;
	for(int i = 20; i>= 0; i--)
	{
		if(dp[i][u] == dp[i][v]) continue;
		u = dp[i][u]; v = dp[i][v];
	}
	return dp[0][u];
}

ll getDist(int u, int v)
{
	int x = LCA(u, v);
	return from[u]+from[v]-from[x]-from[x];
}

int main()
{
	scanf("%d %d %d %d", &n, &k, &q, &e);
	for(int i = 1; i< n; i++)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		way[u].pb(ii(v, i));
		way[v].pb(ii(u, i));
		len[i] = w;
	}
	renumb();
	for(int i = 1; i<= n; i++)
	{
		int u = mp[i];
		for(auto vv : way[i])
		{
			int v = mp[vv.X], id = vv.Y;
			assert(u != v);
			adj[u].pb(ii(v, id));
			adj[v].pb(ii(u, id));
		}
	}
	for(int i = 1; i<= n; i++)
	{
		sort(adj[i].begin(), adj[i].end());
		adj[i].resize(unique(adj[i].begin(), adj[i].end())-adj[i].begin());
	}
	for(int i = 1; i< n; i++)
	{
		road[i] = mp[road[i]];
	}
	for(int i = 1; i<= k; i++)
	{
		int x; scanf("%d", &x);
		isshop[mp[x]] = true;
	}
	// printf("kuy\n");
	centroid(1, 0);
	// printf("okay\n");
	ban.reset();
	findcnt(1, 0);
	util();
	e = mp[e];
	for(int qq = 1; qq<= q; qq++)
	{
		int r, me; scanf("%d %d", &r, &me);
		int st = road[r];
		me = mp[me];
		bool intree = (st<= me && me<= st+cnt[st]-1);
		bool eintree = (st<= e && e<= st+cnt[st]-1);
		if(intree == eintree)
		{
			printf("escaped\n");
			continue;
		}
		int cur = me;
		ll best = 1e18;
		while(cur> 0)
		{
			bool curintree = (st<= cur && cur<= st+cnt[st]-1);
			if(curintree != intree)
			{
				cur = par[cur];
				continue;
			}
			ll go = getDist(cur, me);
			auto tmp = split(root[cur], st-1);
			auto tmp2 = split(tmp.Y, st+cnt[st]-1);
			if(intree)
			{
				if(tmp2.X) best = min(best, go+(tmp2.X)->opt);
			}
			else
			{
				if(tmp.X) best = min(best, go+(tmp.X)->opt);
				if(tmp2.Y) best = min(best, go+(tmp2.Y)->opt);
			}
			auto tmp3 = merge(tmp2.X, tmp2.Y);
			root[cur] = merge(tmp.X, tmp3);
			cur = par[cur];
		}
		if(best == 1e18) printf("oo\n");
		else printf("%lld\n", best);
	}
}

Compilation message (stderr)

valley.cpp: In function 'int main()':
valley.cpp:211:7: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
  scanf("%d %d %d %d", &n, &k, &q, &e);
  ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
valley.cpp:215:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%d %d %d", &u, &v, &w);
   ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
valley.cpp:243:15: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   int x; scanf("%d", &x);
          ~~~~~^~~~~~~~~~
valley.cpp:255:19: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   int r, me; scanf("%d %d", &r, &me);
              ~~~~~^~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...