This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
// Om Namah Shivaya
// GM in 110 days
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
typedef long long int ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define fastio ios_base::sync_with_stdio(false); cin.tie(NULL)
#define endl '\n'
#define pb push_back
#define conts continue
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define yes cout << "YES" << endl
#define no cout << "NO" << endl
#define ff first
#define ss second
#define ceil2(x,y) ((x+y-1) / (y))
#define sz(a) a.size()
#define setbits(x) __builtin_popcountll(x)
#ifndef ONLINE_JUDGE
#define debug(x) cout << #x <<" = "; print(x); cout << endl
#else
#define debug(x)
#endif
#define rep(i,n) for(int i = 0; i < n; ++i)
#define rep1(i,n) for(int i = 1; i <= n; ++i)
#define rev(i,s,e) for(int i = s; i >= e; --i)
#define trav(i,a) for(auto &i : a)
bool iseven(ll n) {if ((n & 1) == 0) return true; return false;}
void print(ll t) {cout << t;}
void print(int t) {cout << t;}
void print(string t) {cout << t;}
void print(char t) {cout << t;}
void print(double t) {cout << t;}
void print(ld t) {cout << t;}
template <class T, class V> void print(pair <T, V> p);
template <class T> void print(vector <T> v);
template <class T> void print(set <T> v);
template <class T, class V> void print(map <T, V> v);
template <class T> void print(multiset <T> v);
template <class T, class V> void print(pair <T, V> p) {cout << "{"; print(p.ff); cout << ","; print(p.ss); cout << "}";}
template <class T> void print(vector <T> v) {cout << "[ "; for (T i : v) {print(i); cout << " ";} cout << "]";}
template <class T> void print(set <T> v) {cout << "[ "; for (T i : v) {print(i); cout << " ";} cout << "]";}
template <class T> void print(multiset <T> v) {cout << "[ "; for (T i : v) {print(i); cout << " ";} cout << "]";}
template <class T, class V> void print(map <T, V> v) {cout << "[ "; for (auto i : v) {print(i); cout << " ";} cout << "]";}
template<typename T> void amin(T &a, T b) { a = min(a, b); }
template<typename T> void amax(T &a, T b) { a = max(a, b); }
void usaco(string filename) {
freopen((filename + ".in").c_str(), "r", stdin);
freopen((filename + ".out").c_str(), "w", stdout);
}
const int MOD = 1e9 + 7;
const int maxn = 3e5 + 5;
const int inf1 = 1e9 + 5;
const ll inf2 = ll(1e18) + 5;
template<typename T>
struct lazysegtree {
/*=======================================================*/
struct data {
ll one, two;
};
struct lazy {
ll a;
};
data d_neutral = {0, 0};
lazy l_neutral = {0};
void merge(data &curr, data &left, data &right) {
curr.one = left.one + right.one;
curr.two = left.two + right.two;
}
void create(int x, int lx, int rx, T v) {
}
void modify(int x, int lx, int rx, T v) {
lz[x].a = v;
}
void propagate(int x, int lx, int rx) {
ll val = lz[x].a;
if (val == 0) return;
ll len = rx - lx;
if (val == 1) tr[x] = {len, 0};
else tr[x] = {0, len};
if (rx - lx > 1) {
lz[2 * x + 1].a = val;
lz[2 * x + 2].a = val;
}
lz[x] = l_neutral;
}
/*=======================================================*/
int siz = 1;
vector<data> tr;
vector<lazy> lz;
lazysegtree() {
}
lazysegtree(int n) {
while (siz < n) siz *= 2;
tr.assign(2 * siz, d_neutral);
lz.assign(2 * siz, l_neutral);
}
void build(vector<T> &a, int n, int x, int lx, int rx) {
if (rx - lx == 1) {
if (lx < n) {
create(x, lx, rx, a[lx]);
}
return;
}
int mid = (lx + rx) / 2;
build(a, n, 2 * x + 1, lx, mid);
build(a, n, 2 * x + 2, mid, rx);
merge(tr[x], tr[2 * x + 1], tr[2 * x + 2]);
}
void build(vector<T> &a, int n) {
build(a, n, 0, 0, siz);
}
void rupd(int l, int r, T v, int x, int lx, int rx) {
propagate(x, lx, rx);
if (lx >= r or rx <= l) return;
if (lx >= l and rx <= r) {
modify(x, lx, rx, v);
propagate(x, lx, rx);
return;
}
int mid = (lx + rx) / 2;
rupd(l, r, v, 2 * x + 1, lx, mid);
rupd(l, r, v, 2 * x + 2, mid, rx);
merge(tr[x], tr[2 * x + 1], tr[2 * x + 2]);
}
void rupd(int l, int r, T v) {
rupd(l, r + 1, v, 0, 0, siz);
}
data query(int l, int r, int x, int lx, int rx) {
propagate(x, lx, rx);
if (lx >= r or rx <= l) return d_neutral;
if (lx >= l and rx <= r) return tr[x];
int mid = (lx + rx) / 2;
data curr;
data left = query(l, r, 2 * x + 1, lx, mid);
data right = query(l, r, 2 * x + 2, mid, rx);
merge(curr, left, right);
return curr;
}
data query(int l, int r) {
return query(l, r + 1, 0, 0, siz);
}
};
lazysegtree<int> st;
vector<int> adj[maxn];
struct lca_algo {
// LCA template (for graphs with 1-based indexing)
int LOG = 1;
vector<int> depth;
vector<vector<int>> up;
lca_algo() {
}
lca_algo(int n) {
lca_init(n);
}
void lca_init(int n) {
while ((1 << LOG) < n) LOG++;
up = vector<vector<int>>(n + 1, vector<int>(LOG));
depth = vector<int>(n + 1);
lca_dfs(1, -1);
}
void lca_dfs(int node, int par) {
trav(child, adj[node]) {
if (child == par) conts;
up[child][0] = node;
rep1(j, LOG - 1) {
up[child][j] = up[up[child][j - 1]][j - 1];
}
depth[child] = depth[node] + 1;
lca_dfs(child, node);
}
}
int lift(int u, int k) {
rep(j, LOG) {
if (k & (1 << j)) {
u = up[u][j];
}
}
return u;
}
int query(int u, int v) {
if (depth[u] < depth[v]) swap(u, v);
int k = depth[u] - depth[v];
u = lift(u, k);
if (u == v) return u;
rev(j, LOG - 1, 0) {
if (up[u][j] != up[v][j]) {
u = up[u][j];
v = up[v][j];
}
}
u = up[u][0];
return u;
}
};
lca_algo LCA;
vector<int> parent(maxn, -1), depth(maxn), heavy(maxn, -1), head(maxn, -1), nodepos(maxn);
int cntr = 1;
int dfs(int node, int par) {
int currsiz = 1, mxsiz = -1;
trav(child, adj[node]) {
if (child == par) conts;
parent[child] = node;
depth[child] = depth[node] + 1;
int childsiz = dfs(child, node);
currsiz += childsiz;
if (childsiz > mxsiz) {
mxsiz = childsiz;
heavy[node] = child;
}
}
return currsiz;
}
void decompose(int node, int par, int leader) {
head[node] = leader;
nodepos[node] = cntr++;
if (heavy[node] != -1) {
decompose(heavy[node], node, leader);
}
trav(child, adj[node]) {
if (child == par or child == heavy[node]) conts;
decompose(child, node, child);
}
}
void rupd(int u, int v, int val) {
if (u == v) return;
for (; head[u] != head[v]; v = parent[head[v]]) {
if (depth[head[u]] > depth[head[v]]) swap(u, v);
st.rupd(nodepos[head[v]], nodepos[v], val);
}
if (depth[u] > depth[v]) swap(u, v);
st.rupd(nodepos[u] + 1, nodepos[v], val);
}
pii query(int u, int v) {
if (u == v) return {0, 0};
int one = 0, two = 0;
for (; head[u] != head[v]; v = parent[head[v]]) {
if (depth[head[u]] > depth[head[v]]) swap(u, v);
auto [val1, val2] = st.query(nodepos[head[v]], nodepos[v]);
one += val1, two += val2;
}
if (depth[u] > depth[v]) swap(u, v);
auto [val1, val2] = st.query(nodepos[u] + 1, nodepos[v]);
one += val1, two += val2;
return {one, two};
}
void solve(int test_case)
{
int n, m; cin >> n >> m;
rep1(i, n - 1) {
int u, v; cin >> u >> v;
adj[u].pb(v), adj[v].pb(u);
}
st = lazysegtree<int>(n + 5);
dfs(1, -1);
decompose(1, -1, 1);
LCA = lca_algo(n);
int ans = 1;
while (m--) {
int u, v; cin >> u >> v;
int lca = LCA.query(u, v);
auto [one1, two1] = query(u, lca);
auto [one2, two2] = query(v, lca);
if (one1 == 0 and two1 == 0 and one2 == 0 and two2 == 0) {
ans = (ans * 2) % MOD;
rupd(u, lca, 1);
rupd(v, lca, 2);
}
else {
if ((one1 and one2) or (two1 and two2)) {
cout << 0 << endl;
return;
}
if (one1 or two2) {
rupd(u, lca, 1);
rupd(v, lca, 2);
}
else {
rupd(u, lca, 2);
rupd(v, lca, 1);
}
}
}
rep1(u, n) {
trav(v, adj[u]) {
if (u != parent[v]) conts;
int lca = u;
auto [one, two] = query(v, lca);
if (one == 0 and two == 0) {
ans = (ans * 2) % MOD;
}
}
}
cout << ans << endl;
}
int main()
{
fastio;
int t = 1;
// cin >> t;
rep1(i, t) {
solve(i);
}
return 0;
}
Compilation message (stderr)
usmjeri.cpp: In function 'void usaco(std::string)':
usmjeri.cpp:64:12: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
64 | freopen((filename + ".in").c_str(), "r", stdin);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
usmjeri.cpp:65:12: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
65 | freopen((filename + ".out").c_str(), "w", stdout);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |