#include #include using namespace std; using ll=long long; using ld=double; using vll=vector; using vvll=vector>; #define FOR(i,a,b) for(ll i=a;i<(ll)b;++i) #define F(n) FOR(i,0,n) #define FF(n) FOR(j,0,n) #define aa first #define bb second #define PB push_back #define EQ(a,b) (fabs(a-b)<=(fabs(a+b)*EPS)) #define MOD ((ll)(1e9+7)) #define dbg cerr #define out(n) cout << n << endl #define INF (1ll << 40) //#define dbg if(0)cerr vvll g; ll n; bool shouldDefend; ll minGuards() { ll res=1; F(g.size()) { res += (g[i].size() > 1); } return res; } vll initialPlacement() { vll res; F(g.size()) if (g[i].size() == 1) { res.PB(i); break; } F(g.size()) if (g[i].size() > 1) res.PB(i); return res; } void print(const vll & a){ for (auto i: a) cout << i << ' '; cout << endl; } ll readAttack() { ll t; cin>>t; if (t == -1) { exit(0); } return t; } bool has(vll & a, ll n) { for (auto i: a) if (i == n) return 1; return 0; } bool dfs(ll v, ll prev, ll goal, const set & allowed, vector> & res) { //dbg << "dfs: " << v << endl; if (v == goal) { //out(prev << ' ' << v); res.PB({prev,v}); return true; } for (auto i: g[v]){ if (i == prev || (!allowed.count(i) && i != goal)) continue; if (dfs(i, v, goal, allowed, res)) { if (prev != -1) res.PB({prev,v}); return true; } } return false; } void marchGuards(int from, int to, vll & pl) { //dbg << "march from " << from << " to " << to << endl; set pls(pl.begin(), pl.end()); vector> res; if (!dfs(from, -1, to, pls, res)) { //dbg << "found no way to defend, losing :(" << endl; dbg << "ATTACKER WINS" << endl; assert(!shouldDefend); exit(0); } out(res.size()); for (auto j: res) cout << j.aa << ' ' << j.bb << endl; pls.erase(from); pls.insert(to); pl.clear(); pl.insert(pl.end(), pls.begin(), pls.end()); } void defendMyself(vll & pl, ll at) { // find the occupied leaf dbg << "defending" << endl; // if occupied, do not move if (find(pl.begin(), pl.end(), at) != pl.end()) { out(0); return; } // optimal move is to move with a leaf. If it is not possible, pick a vertex on random for (auto i: pl) { if (g[i].size() == 1) { marchGuards(i, at, pl); return; } } ll picked = pl[0]; F(pl.size()) if (rand()%(i+1) == 0) picked = pl[i]; marchGuards(picked, at, pl); } // compute the difference between the required and actual number of guards in each subtree, if each subtree had no edge to the parent ll dfs2(ll v, ll prev, vll & mem, const set & pls) { ll res = pls.count(v) - (g[v].size() > 1); for (auto i: g[v]) { if (i == prev) continue; res += dfs2(i, v, mem, pls); } mem[v] = res - 1; return res; } // compute depth for each node void dfs3(ll v, ll prev, vll & mem, ll dep) { mem[v] = dep; for (auto i: g[v]) { if (i == prev) continue; dfs3(i, v, mem, dep+1); } } // find some leaf of a given subtree ll dfs4(ll v, vll & depth) { if (g[v].size() == 1) return v; for (auto i: g[v]) { if (depth[i] > depth[v]) return dfs4(i, depth); } assert(false); } ll attackOnEnemy(ll root, const vll & pl) { vll surplus(n), depth(n); set pls(pl.begin(), pl.end()); dfs2(root, -1, surplus, pls); dfs3(root, -1, depth, 0); // find undefended leaf and parent F(n) { if (g[i].size() == 1 && !pls.count(i) && !pls.count(g[i][0])) { dbg << "won!!!!!! Muhahahahaha >:O" << endl; return i; } } // check if all red vertices are occupied, if so attack on a leaf bool anyRedUnoccupied=false; F(n) { if (g[i].size() > 1 && !pls.count(i)) anyRedUnoccupied = true; } if (!anyRedUnoccupied) { F(n) if (g[i].size() == 1) { return i; } } // there is some deficient subtree with no guard, find the one deficient subtree and attack its leaf pair best = {-INF, -INF}; F(n){ if (!pls.count(i) && surplus[i] < 0 && g[i].size() > 1) { FF(g[i].size()) { if (depth[g[i][j]] > depth[i] && surplus[g[i][j]] < 0) { return dfs4(g[i][j], depth); } } } } assert(false); } // returns either one or two vertices vector treeCenters(const vector> & g) { ll n = g.size(); vector depth(n, -1); queue q; F(n) if (g[i].size() == 1) { q.push(i); depth[i] = 0; } while (q.size()) { ll cur = q.front(); q.pop(); F(g[cur].size()) { if (depth[g[cur][i]] == -1) { q.push(g[cur][i]); depth[g[cur][i]] = depth[cur] + 1; } } } ll mx = -1; F(n) mx = max(depth[i], mx); vector res; F(n) if (depth[i] == mx) res.PB(i); return res; } char tt; void test(int guards) { vll pl = initialPlacement(); // optimal number of guards //pl.pop_back(); // make it one less than optimal //pl.erase(find(pl.begin(), pl.end(), 3)); while (pl.size() > guards) { swap(pl[pl.size()-1], pl[rand()%pl.size()]); pl.pop_back(); } //dbg << "initial placement: " << endl; print(pl); ll root = treeCenters(g)[0]; //dbg << "rooted at " << root << endl; F(1000){ ll at = attackOnEnemy(root, pl); dbg << "attacking on " << at << "!" << endl; #ifdef WAITFORKEY cin>>tt; #endif if (has(pl,at)) out("0"); else { defendMyself(pl, at); } #ifdef WAITFORKEY cin>>tt; #endif } assert(shouldDefend); dbg << "DEFENDER WINS" << endl; exit(0); } vll readPlacement(ll gd) { vll pl(gd); F(gd)cin>>pl[i]; dbg << "current placement: " << endl; for (auto i: pl) dbg << i << ' '; dbg << endl; return pl; } void updateByMoves(vll & pl) { ll k; cin>>k; multiset pls(pl.begin(),pl.end()); F(k){ ll u,v; cin>>u>>v; pls.erase(pls.find(u)); pls.insert(v); } pl.clear(); pl.insert(pl.begin(), pls.begin(), pls.end()); } int main(){ ios::sync_with_stdio(0);cin.tie(0); srand(time(0)); //dbg << "Let's play a game >:)" << endl; ll gd; cin>>n>>gd; g=vvll(n); F(n-1){ ll u,v; cin>>u>>v; g[u].PB(v); g[v].PB(u); } bool defend=0; //dbg << "min guards: " << minGuards() << endl; /*gd = minGuards()-1;*/ if (gd >= minGuards()){ out("DEFEND"); shouldDefend=1; defend=1; } else { shouldDefend=0; out("ATTACK"); } //test(gd); if (defend) { dbg << "defending" << endl; vll pl = initialPlacement(); print(pl); F(1000){ ll at = readAttack(); defendMyself(pl, at); } } else { // attack dbg << "attacking" << endl; ll root = treeCenters(g)[0]; dbg << "rooted at " << root << endl; vll pl = readPlacement(gd); dbg << "got the placement, planning my next attack >:)" << endl; out(attackOnEnemy(root, pl)); updateByMoves(pl); } return 0; }