1. 程式人生 > >WC2018 即時戰略

WC2018 即時戰略

戰略 點分治 調用 pac hid long long ota lap rotate

交互題

一棵樹,一開始只有 1 號點是已知的,其他的都是未知的,你可以調用函數 explore(x,y) ,其中 x 必須是已知的,函數會找到 x 到 y 路徑上第二個點,並把它標成已知,求最小步數使整棵樹都已知

對於 30% 的數據,是一條鏈,操作次數 $O(n+logn)$

剩下的數據,操作次數 $O(nlogn)$

$n \leq 300000$

sol:

先吐槽 loj 的交互題評測機制

把 ac 時應該輸出的東西輸出,然後就 a 了

不 shing 話

鏈的情況想了半天,題解是 xjb 暴力,服

因為這個 explore 的性質,當前已知的一定是一條線段

維護一下當前已知的左端點和右端點,每次隨機一個未知的點蹦過去,如果走錯方向了就換個方向走

這樣出錯次數期望 log ? 不知道

樹的情況很好想

首先想到一個很樸素的暴力,對於每個點,從根 explore 下去

然後會發現自己多 explore 了很多已知的點,當需要 explore 一個點的時候你只需要跳到他那個子樹上,從那個點開始 explore 就可以了

現在就是要維護一棵樹滋磁

1.加入一個點

2.快速跳到一個點

動態點分治/LCT 都可以

但誰都知道 LCT 好寫吧...於是果斷 LCT

每次操作後 access 保證復雜度即可

至於為什麽 access?道理相當於 splay 每次把查詢點旋到根保證復雜度?

什麽?uoj 有 hack 數據?random_shuffle 一下就可以了

跑到了 rk#3 應該是比較歐的原因

因為之後再也跑不了那麽快了

技術分享圖片
#include <bits/stdc++.h>
#include "rts.h"
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline 
int read() { int x = 0, f = 1; char ch; for (ch = getchar(); !isdigit(ch); ch = getchar()) if (ch == -) f = -f; for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - 0; return x * f; } const int maxn = 300010; #define ls ch[x][0] #define rs ch[x][1] int vis[maxn], pid[maxn]; int fa[maxn], ch[maxn][2], mn[maxn], mx[maxn]; inline int isroot(int x) { return ((ch[fa[x]][0] != x) && (ch[fa[x]][1] != x)); } inline void pushup(int x) { mn[x] = mx[x] = x; if (ls) mn[x] = mn[ls]; if (rs) mx[x] = mx[rs]; } inline void rotate(int x) { int y = fa[x], z = fa[y]; int l = (ch[y][1] == x), r = l ^ 1; if (!isroot(y)) ch[z][ch[z][1] == y] = x; fa[x] = z; fa[ch[x][r]] = y; fa[y] = x; ch[y][l] = ch[x][r]; ch[x][r] = y; pushup(y); pushup(x); } inline void splay(int x) { while (!isroot(x)) { int y = fa[x], z = fa[y]; if (!isroot(y)) { if (ch[z][0] == y ^ ch[y][0] == x) rotate(x); else rotate(y); } rotate(x); } pushup(x); } void access(int x) { for (int y = 0; x; y = x, x = fa[x]) { splay(x); rs = y; pushup(x); } } inline int findroot(int x) { while (!isroot(x)) x = fa[x]; return x; } void play(int n, int T, int dataType) { // srand((unsigned long long)new char); for (int i = 2; i <= n; i++) pid[i] = i; random_shuffle(pid + 2, pid + n + 1); if (dataType == 3) // chain { vis[1] = 1; int l = 1, r = 1; for (int i = 2; i <= n; i++) { int x = pid[i], now; if (vis[x]) continue; if (!vis[now = explore(l, x)]) { while (now != x) vis[now] = 1, now = explore(now, x); vis[x] = 1; l = x; } else { now = explore(r, x); while (now != x) vis[now] = 1, now = explore(now, x); vis[x] = 1; r = x; } } } else { vis[1] = 1; mn[1] = mx[1] = 1; for (int i = 2; i <= n; i++) { if (vis[pid[i]]) continue; int now = pid[i], x = findroot(1), ret; while (!vis[now]) { ret = explore(x, now); if (mn[rs] == ret) x = rs; else if (mx[ls] == ret) x = ls; else if (vis[ret]) x = findroot(ret); else vis[ret] = 1, mn[ret] = mx[ret] = ret, fa[ret] = x, x = ret; } access(now); } } }
View Code

WC2018 即時戰略