#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;
typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;
typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;
template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;
#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()
const int MOD = 1000000007;
const pi INF = {-MOD,MOD};
const int MX = 100001;
#define LOCAL
#ifdef LOCAL
#else
#include "catdog.h"
#endif
// UTILITY
pi operator + (const pi& l, const pi& r) {
if (l == INF) return l;
return {l.f+r.f,l.s+r.s};
}
pi operator += (pi& l, const pi& r) { return l = l+r; }
pi operator + (const pi& l, const int& r) { return l+mp(r,r); }
pi operator += (pi& l, const int& r) { return l = l+r; }
pi operator - (const pi& l, const pi& r) {
if (l == INF) return l;
return {l.f-r.f,l.s-r.s};
}
pi operator -= (pi& l, const pi& r) { return l = l-r; }
pi comb(pi x, pi y) {
if (x == mp(-MOD,MOD)) return x;
return {min(x.f,y.f),max(x.s,y.s)};
}
pi neg(pi a) { return {-a.f,-a.s}; }
template<int SZ> struct L {
typedef pi T;
T dif[2*SZ], lazy[2*SZ]; // set SZ to a power of 2
L() {
memset (dif,0,sizeof dif);
memset (lazy,0,sizeof lazy);
}
void ad(int ind, pi x) {
lazy[ind] += x;
dif[ind] += x.f-x.s;
}
void push(int ind, int L, int R) {
if (L == R) return;
if (L != R) {
ad(2*ind,lazy[ind]);
ad(2*ind+1,lazy[ind]);
}
lazy[ind] = {0,0};
}
void pull(int ind) { dif[ind] = comb(dif[2*ind],dif[2*ind+1]); }
/*T query(int lo, int hi, int ind = 1, int L = 0, int R = SZ-1) { // get difference
push(ind,L,R);
if (lo > R || L > hi) return neg(INF);
if (lo <= L && R <= hi) return dif[ind];
int M = (L+R)/2;
return comb(query(lo,hi,2*ind,L,M), query(lo,hi,2*ind+1,M+1,R));
}*/
T getLazy(int x, int ind = 1, int L = 0, int R = SZ-1) { // OK
if (L == R) return lazy[ind];
push(ind,L,R);
int M = (L+R)/2;
if (x <= M) return getLazy(x,2*ind,L,M);
return getLazy(x,2*ind+1,M+1,R);
}
void upd(int lo, int hi, T inc, int ind = 1, int L = 0, int R = SZ-1) {
push(ind,L,R);
if (hi < L || R < lo) return;
if (lo <= L && R <= hi) {
ad(ind,inc);
push(ind,L,R);
return;
}
int M = (L+R)/2;
upd(lo,hi,inc,2*ind,L,M); upd(lo,hi,inc,2*ind+1,M+1,R);
pull(ind);
}
void adDif(int x, int z, int ind = 1, int L = 0, int R = SZ-1) { // TODO
if (x < L || x > R) return;
if (L == R) {
if (z == -1) {
dif[ind] = mp(0,0)+(lazy[ind].f-lazy[ind].s);
} else {
dif[ind] = INF;
}
return;
}
push(ind,L,R);
int M = (L+R)/2;
adDif(x,z,2*ind,L,M); adDif(x,z,2*ind+1,M+1,R);
pull(ind);
}
int getFst(int x, pi t, int ind = 1, int L = 0, int R = SZ-1) { // TODO
push(ind,L,R);
int M = (L+R)/2;
if (L == R) {
if (comb(t,dif[ind]) == t) return L;
return L+1;
}
if (x <= M) return getFst(x,t,2*ind,L,M);
if (x <= R) {
int tmp = getFst(x,t,2*ind+1,M+1,R);
if (tmp != M+1) return tmp;
return getFst(x,t,2*ind,L,M);
}
if (comb(t,dif[2*ind+1]) != t) return getFst(x,t,2*ind+1,M+1,R);
return getFst(x,t,2*ind,L,M);
/*
int tmp = getFst(x,t,2*ind+1,M+1,R);
if (tmp == M+1) return getFst(x,t,2*ind,L,M);
return tmp;*/
}
};
vector<vi> graph;
template <int V> struct HeavyLight { // sum queries, sum updates
int parent[V], heavy[V], depth[V];
int root[V], treePos[V], rTreePos[V];
L<V> val, child;
void init() {
int n = sz(graph)-1;
FOR(i,1,n+1) heavy[i] = -1;
parent[1] = -1, depth[1] = 0;
dfs(1);
for (int i = 1, currentPos = 0; i <= n; ++i)
if (parent[i] == -1 || heavy[parent[i]] != i)
for (int j = i; j != -1; j = heavy[j]) {
root[j] = i;
treePos[j] = currentPos;
rTreePos[currentPos] = j;
currentPos ++;
}
}
int dfs(int v) {
int size = 1, maxSubtree = 0;
for (auto u : graph[v]) if (u != parent[v]) {
parent[u] = v;
depth[u] = depth[v] + 1;
int subtree = dfs(u);
if (subtree > maxSubtree) heavy[v] = u, maxSubtree = subtree;
size += subtree;
}
return size;
}
template <class BinaryOperation>
void processPath(int u, int v, BinaryOperation op) {
for (; root[u] != root[v]; v = parent[root[v]]) {
if (depth[root[u]] > depth[root[v]]) swap(u, v);
op(treePos[root[v]], treePos[v]);
}
if (depth[u] > depth[v]) swap(u, v);
op(treePos[u], treePos[v]); // assumes values are stored in vertices
}
pi get(int x) { return val.getLazy(treePos[x]); }
void upd(int x, int y, pi z) {
if (y == 0) return;
// cout << "OH " << x << " " << y << "\n";
processPath(x,y,[this, &z](int l, int r) { val.upd(l,r,z); });
if (y != 1) {
//cout << "HI " << max(1,parent[x]) << " " << parent[y] << " " << z << "\n";
processPath(max(1,parent[x]),parent[y],[this, &z](int l, int r) { child.upd(l,r,z); });
//cout << child.getLazy(treePos[1]) << "\n";
}
}
void adDif(int v, int x) { child.adDif(treePos[v],x); }
int getFst(int v, pi x) { // TODO
int lst = v; v = parent[v];
while (v) {
int t = child.getFst(treePos[v],x);
if (t > treePos[root[v]]) {
if (t == treePos[v]+1) return lst;
// cout << "AH " << t << " " << rTreePos[t] << "\n";
return rTreePos[t];
}
lst = root[v]; v = parent[lst];
}
return 1;
}
};
HeavyLight<1<<17> H;
int N, st[MX];
pi trans(int v, pi x) {
switch(v) {
case 1: return {x.f,x.f+1};
case 2: return {x.s+1,x.s};
default:
x.s = min(x.s,x.f+1);
x.f = min(x.f,x.s+1);
return x;
}
}
int query() {
pi x = H.get(1);
return min(x.f,x.s);
}
void initialize(int n, std::vector<int> A, std::vector<int> B) {
N = n;
graph.resize(N+1);
F0R(i,N-1) graph[A[i]].pb(B[i]), graph[B[i]].pb(A[i]);
H.init();
}
pi eval(int v) { return trans(st[v],H.child.getLazy(H.treePos[v])); }
ostream& operator<<(ostream& o, const pi& x) {
o << x.f << " " << x.s << " | ";
return o;
}
void upd(int v, pi x) {
int m = min(x.f,x.s);
H.upd(1,v,{m,m});
x.f -= m, x.s -= m;
while (x.f || x.s) {
int z;
if (x.f) {
z = H.getFst(v,{-1,0});
H.upd(z,v,{1,0});
x.f --;
} else {
z = H.getFst(v,{0,1});
H.upd(z,v,{0,1});
x.s --;
}
if (z > 1) {
pi t = eval(H.parent[z])-H.get(H.parent[z]);
if (t.f != t.s) {
cout << "BAD " << z << " " << v << "\n" << st[H.parent[z]] << " " << eval(H.parent[z]) << "\n" << H.get(H.parent[z]) << "\n";
exit(0);
}
H.upd(1,H.parent[z],t);
}
}
}
int change(int ind, int v) {
if (st[v]) H.adDif(v,-1);
st[v] = ind;
if (st[v]) H.adDif(v,1);
upd(v,eval(v)+neg(H.get(v)));
pi x = H.get(1);
if (x.f < 0 || x.s < 0) {
// cout << H.get(2) << " " << " | " << H.get(1) << " " << "|" << " " << H.child.getLazy(1) << " " << eval(1) << "\n";
exit(0);
}
return min(x.f,x.s);
}
int cat(int v) { return change(1,v); }
int dog(int v) { return change(2,v); }
int neighbor(int v) { return change(0,v); }
#ifdef LOCAL
int readInt(){
int i;
if(scanf("%d",&i)!=1){
fprintf(stderr,"Error while reading input\n");
exit(1);
}
return i;
}
int main(){
int N=readInt();
std::vector<int> A(N-1),B(N-1);
for(int i=0;i<N-1;i++)
{
A[i]=readInt();
B[i]=readInt();
}
int Q;
assert(scanf("%d",&Q)==1);
std::vector <int> T(Q),V(Q);
for(int i=0;i<Q;i++)
{
T[i]=readInt();
V[i]=readInt();
}
initialize(N,A,B);
std::vector<int> res(Q);
for(int j=0;j<Q;j++)
{
if(T[j]==1) res[j]=cat(V[j]);
else if(T[j]==2) res[j]=dog(V[j]);
else res[j]=neighbor(V[j]);
if (res[j] < 0) cout << "AH " << j << " " << T[j] << " " << V[j] << "\n";
}
for(int j=0;j<Q;j++)
printf("%d\n",res[j]);
return 0;
}
#endif
/*
0
1
1
2
1
*/
/* Look for:
* the exact constraints (multiple sets are too slow for n=10^6 :( )
* special cases (n=1?)
* overflow (ll vs int?)
* array bounds
*/
Compilation message
/tmp/ccpyhJ7w.o: In function `readInt()':
grader.cpp:(.text+0x0): multiple definition of `readInt()'
/tmp/ccUipmj6.o:catdog.cpp:(.text+0x1120): first defined here
/tmp/ccpyhJ7w.o: In function `main':
grader.cpp:(.text.startup+0x0): multiple definition of `main'
/tmp/ccUipmj6.o:catdog.cpp:(.text.startup+0x0): first defined here
collect2: error: ld returned 1 exit status