結果
| 問題 |
No.363 門松サイクル
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2016-04-23 12:44:22 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 472 ms / 4,000 ms |
| コード長 | 4,792 bytes |
| コンパイル時間 | 1,465 ms |
| コンパイル使用メモリ | 124,388 KB |
| 実行使用メモリ | 36,464 KB |
| 最終ジャッジ日時 | 2024-10-11 00:02:47 |
| 合計ジャッジ時間 | 9,316 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 27 |
ソースコード
#define _USE_MATH_DEFINES
#include <cstdio>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <complex>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <limits>
#include <climits>
#include <cfloat>
#include <functional>
using namespace std;
class LowestCommonAncestor
{
private:
vector<vector<int> > to;
vector<int> depth;
public:
LowestCommonAncestor()
{}
LowestCommonAncestor(const vector<vector<int> >& edges, int root)
{
int n = edges.size();
to.assign(n, vector<int>());
depth.resize(n);
stack<tuple<int, int, int, int> > stk;
stk.push(make_tuple(root, -1, 0, 0));
while(!stk.empty()){
int curr, prev, cnt, i;
tie(curr, prev, cnt, i) = stk.top();
stk.pop();
if(i == 0){
depth[curr] = cnt;
if(prev != -1){
to[curr].push_back(prev);
int j = prev;
for(unsigned k=0; k<to[j].size(); ++k){
j = to[j][k];
to[curr].push_back(j);
}
}
}
if(i < (int)edges[curr].size()){
stk.push(make_tuple(curr, prev, cnt, i + 1));
int next = edges[curr][i];
if(next != prev)
stk.push(make_tuple(next, curr, cnt + 1, 0));
}
}
}
int climb(int curr, int dist)
{
int i = 0;
while(dist > 0){
if(dist % 2 == 1)
curr = to[curr][i];
dist /= 2;
++ i;
}
return curr;
}
// 2つのノードの最小共通祖先を取得
int getAncestor(int a, int b)
{
int diff = depth[a] - depth[b];
if(diff < 0)
b = climb(b, -diff);
else
a = climb(a, diff);
if(a == b)
return a;
for(int i=to[a].size()-1; i>=0; --i){
if(i < (int)to[a].size() && to[a][i] != to[b][i]){
a = to[a][i];
b = to[b][i];
}
}
return to[a][0];
}
// ノードの深さを取得
int getDepth(int a)
{
return depth[a];
}
// 2つのノードの距離を取得
int getDist(int a, int b)
{
int c = getAncestor(a, b);
return getDepth(a) + getDepth(b) - getDepth(c) * 2;
}
};
bool checkKadomatsu(const vector<int>& a)
{
if(a[0] == a[2])
return false;
return (a[0] < a[1] && a[2] < a[1]) || (a[0] > a[1] && a[2] > a[1]);
}
int n;
vector<int> a;
vector<vector<int> > edges;
vector<int> cnt;
LowestCommonAncestor lca;
void dfs(int curr, int prev, int prev2)
{
if(prev2 != -1 && checkKadomatsu({a[curr], a[prev], a[prev2]}))
cnt[curr] = cnt[prev] + 1;
for(int next : edges[curr]){
if(next != prev)
dfs(next, curr, prev);
}
}
bool solve(int u, int v)
{
if(lca.getDist(u, v) < 2)
return false;
int w = lca.getAncestor(u, v);
int du = lca.getDist(u, w);
int dv = lca.getDist(v, w);
if(u == w || v == w){
if(u == w){
swap(u, v);
swap(du, dv);
}
int u2 = lca.climb(u, du - 1);
if(cnt[u] - cnt[u2] < du - 1)
return false;
int u3 = lca.climb(u, 1);
return checkKadomatsu({a[u3], a[u], a[v]}) && checkKadomatsu({a[u], a[v], a[u2]});
}
else{
int u2 = lca.climb(u, du - 1);
if(cnt[u] - cnt[u2] < du - 1)
return false;
int v2 = lca.climb(v, dv - 1);
if(cnt[v] - cnt[v2] < dv - 1)
return false;
if(!checkKadomatsu({a[u2], a[w], a[v2]}))
return false;
int u3 = lca.climb(u, 1);
int v3 = lca.climb(v, 1);
return checkKadomatsu({a[u3], a[u], a[v]}) && checkKadomatsu({a[u], a[v], a[v3]});
}
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
cin >> n;
a.resize(n);
for(int i=0; i<n; ++i)
cin >> a[i];
edges.assign(n, vector<int>());
for(int i=0; i<n-1; ++i){
int x, y;
cin >> x >> y;
-- x;
-- y;
edges[x].push_back(y);
edges[y].push_back(x);
}
lca = LowestCommonAncestor(edges, 0);
cnt.assign(n, 0);
dfs(0, -1, -1);
int q;
cin >> q;
while(--q >= 0){
int u, v;
cin >> u >> v;
-- u;
-- v;
if(solve(u, v))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}