Last active
July 21, 2020 09:57
-
-
Save gghatano/7d512b9f23b0bf964fd60fa713991372 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
// #include <boost/multiprecision/cpp_int.hpp> | |
using namespace std; | |
// using namespace boost::multiprecision; | |
# define REP(i,n) for (int i=0;i<(n);++i) | |
# define rep(i,a,b) for(int i=a;i<(b);++i) | |
# define all(v) v.begin(),v.end() | |
# define showVector(v) REP(i,v.size()){cout << (v[i]) << " ";} cout << endl; | |
template<class T> inline bool chmin(T &a, T b){ if(a > b) { a = b; return true;} return false;} | |
template<class T> inline bool chmax(T &a, T b){ if(a < b) { a = b; return true;} return false;} | |
typedef long long int ll; | |
typedef pair<ll,ll> P_ii; | |
typedef pair<double,double> P_dd; | |
template<class T> | |
using MaxHeap = std::priority_queue<T>; | |
template<class T> | |
using MinHeap = std::priority_queue<T, std::vector<T>, std::greater<T>>; | |
// 多次元 vector 生成 | |
template<class T> | |
vector<T> make_vec(size_t a){ | |
return vector<T>(a); | |
} | |
template<class T, class... Ts> | |
auto make_vec(size_t a, Ts... ts){ | |
return vector<decltype(make_vec<T>(ts...))>(a, make_vec<T>(ts...)); | |
} | |
template<typename T> | |
T gcd(T a, T b) { | |
if(a < b) swap(a,b); | |
if(b == 0) return a; | |
return gcd(b, a % b); | |
} | |
ll lcm(ll a, ll b){ | |
ll g = gcd(a,b); | |
return (a/g)*b; | |
} | |
// 素数判定 O(√n) | |
bool is_prime(ll n){ | |
if(n == 1) return false; | |
for(ll i = 2; i * i <= n; i++){ | |
if(n % i == 0) return false; | |
} | |
return true; | |
} | |
// 約数列挙 O(√n) | |
vector<ll> divisor(ll n){ | |
vector<ll> res; | |
for(ll i = 1; i * i <= n; i++){ | |
if(n % i == 0){ | |
res.push_back(i); | |
if(i != n / i) res.push_back(n / i); | |
} | |
} | |
return res; | |
} | |
template<typename T> | |
// エラトステネスの篩 | |
// return lp[i] := iの最小素因数(lp[i] == iならば素数) | |
vector<int> SieveOfEratosthenes(int N = 10000000){ | |
vector<int> lp(N + 1, 0); | |
vector<int> pr; | |
for (int i=2; i<=N; ++i) { | |
if (lp[i] == 0) { | |
lp[i] = i; | |
pr.push_back(i); | |
} | |
for (int j=0; j<(int)pr.size() && pr[j]<=lp[i] && i*pr[j]<=N; ++j) | |
lp[i * pr[j]] = pr[j]; | |
} | |
return lp; | |
} | |
// modint | |
const ll mod = 1e9+7; | |
template< int mod > | |
struct ModInt { | |
int x; | |
ModInt() : x(0) {} | |
ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {} | |
ModInt &operator+=(const ModInt &p) { | |
if((x += p.x) >= mod) x -= mod; | |
return *this; | |
} | |
ModInt &operator-=(const ModInt &p) { | |
if((x += mod - p.x) >= mod) x -= mod; | |
return *this; | |
} | |
ModInt &operator*=(const ModInt &p) { | |
x = (int) (1LL * x * p.x % mod); | |
return *this; | |
} | |
ModInt &operator/=(const ModInt &p) { | |
*this *= p.inv(); | |
return *this; | |
} | |
ModInt operator-() const { return ModInt(-x); } | |
ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; } | |
ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; } | |
ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; } | |
ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; } | |
bool operator==(const ModInt &p) const { return x == p.x; } | |
bool operator!=(const ModInt &p) const { return x != p.x; } | |
ModInt inv() const { | |
int a = x, b = mod, u = 1, v = 0, t; | |
while(b > 0) { | |
t = a / b; | |
swap(a -= t * b, b); | |
swap(u -= t * v, v); | |
} | |
return ModInt(u); | |
} | |
ModInt pow(int64_t n) const { | |
ModInt ret(1), mul(x); | |
while(n > 0) { | |
if(n & 1) ret *= mul; | |
mul *= mul; | |
n >>= 1; | |
} | |
return ret; | |
} | |
friend ostream &operator<<(ostream &os, const ModInt &p) { | |
return os << p.x; | |
} | |
friend istream &operator>>(istream &is, ModInt &a) { | |
int64_t t; | |
is >> t; | |
a = ModInt< mod >(t); | |
return (is); | |
} | |
static int get_mod() { return mod; } | |
}; | |
using mint = ModInt<mod>; | |
ll mypow(ll x, ll n){ | |
if(n == 0) | |
return 1; | |
if(n % 2 == 0) | |
return mypow(x * x, n / 2); | |
else | |
return x * mypow(x, n - 1); | |
} | |
// 素因数分解 | |
long long MOD = 1000000000 + 7; | |
template<typename T> | |
map<T, ll> prime_factorize(T x){ | |
map<T, ll> res; | |
while(x%2==0){ | |
x/=2; | |
res[2]++; | |
} | |
for(ll i=3;i*i<=x;i+=2){ | |
while(x%i==0){ | |
x/=i; | |
res[i]++; | |
} | |
} | |
if(x!=1) res[x]++; | |
return res; | |
} | |
// ランレングス圧縮 | |
vector<pair<char,int>> run_comp(string S){ | |
vector<pair<char,int>> v; | |
char now = S[0]; | |
int num = 1; | |
char tmp = S[S.size()-1]; | |
for(int i = 1; i < S.size(); i++){ | |
tmp = S[i]; | |
if(now == tmp){ | |
num++; | |
} else { | |
v.push_back(make_pair(now, num)); | |
num = 1; | |
now = tmp; | |
} | |
} | |
v.push_back(make_pair(tmp, num)); | |
return v; | |
} | |
// union find | |
struct UnionFind { | |
vector<int> data; | |
UnionFind(int size) : data(size, -1) { } | |
bool unionSet(int x, int y) { | |
x = root(x); y = root(y); | |
if (x != y) { | |
if (data[y] < data[x]) swap(x, y); | |
data[x] += data[y]; data[y] = x; | |
} | |
return x != y; | |
} | |
bool findSet(int x, int y) { | |
return root(x) == root(y); | |
} | |
int root(int x) { | |
return data[x] < 0 ? x : data[x] = root(data[x]); | |
} | |
int size(int x) { | |
return -data[root(x)]; | |
} | |
}; | |
// nCrの計算 | |
const int MAX = 510000; | |
const int MOD = 1000000007; | |
long long fac[MAX], finv[MAX], inv[MAX]; | |
// テーブルを作る前処理 | |
void COMinit() { | |
fac[0] = fac[1] = 1; | |
finv[0] = finv[1] = 1; | |
inv[1] = 1; | |
for (int i = 2; i < MAX; i++){ | |
fac[i] = fac[i - 1] * i % MOD; | |
inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD; | |
finv[i] = finv[i - 1] * inv[i] % MOD; | |
} | |
} | |
// 二項係数計算 | |
long long COM(int n, int k){ | |
if (n < k) return 0; | |
if (n < 0 || k < 0) return 0; | |
return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD; | |
} | |
int main() { | |
// 前処理 | |
COMinit(); | |
// 計算例 | |
cout << COM(100000, 50000) << endl; | |
} | |
/* 大文字を小文字に変換 */ | |
char tolower(char c) { | |
return (c + 0x20); | |
} | |
/* 小文字を大文字に変換 */ | |
char toupper(char c) { | |
return (c - 0x20); | |
} | |
// dijkstra法 | |
ll INF = 10000000000000000; | |
vector<vector<int>> v; | |
vector<ll> dist; | |
map<pii, ll> len; | |
bool operator>(pil x, pil y){ | |
return x.second > y.second; | |
} | |
void shortest_path(int s){ | |
// sから各点への最短距離計算 | |
dist.assign(N,INF); | |
priority_queue<pil, vector<pil>, greater<pil>> q; | |
dist[s] = 0; | |
map<int,int> check; | |
q.push(make_pair(s, dist[s])); | |
check[s] = 1; | |
while(!q.empty()){ | |
pil now = q.top(); | |
int now_v = now.first; | |
ll now_dist = now.second; | |
check[now_v] = 1; | |
q.pop(); | |
if(dist[now_v] < now_dist) continue; | |
for(int next_v: v.at(now_v)){ | |
if(dist[next_v] > dist[now_v] + len[make_pair(now_v, next_v)]){ | |
dist[next_v] = dist[now_v] + len[make_pair(now_v, next_v)]; | |
q.push(make_pair(next_v, dist[next_v])); | |
} | |
} | |
} | |
} | |
// LCS | |
string LCS(string s, string t){ | |
int n, m; | |
n = s.length(); | |
m = t.length(); | |
// dp[i][j] : sのi文字目、tのj文字目のLCSの長さ | |
vector<vector<int>> dp(n+1, vector<int>(m+1, 0)); | |
for(int i = 1; i <= n; i++){ | |
for(int j = 1; j <= m; j++){ | |
if(s[i-1] == t[j-1]){ | |
dp[i][j] = dp[i-1][j-1] + 1; | |
}else{ | |
dp[i][j] = max(dp[i-1][j], dp[i][j-1]); | |
} | |
} | |
} | |
// dp配列を逆からたどってLCSを作成する | |
// LCSの長さが更新されたときの文字を追加していく | |
string ans = ""; | |
int x = n; | |
int y = m; | |
while(x > 0 && y > 0){ | |
if(dp[x][y] == dp[x-1][y]){ | |
x--; | |
}else if(dp[x][y] == dp[x][y-1]){ | |
y--; | |
}else{ | |
x--; | |
y--; | |
ans += s[x]; | |
} | |
} | |
reverse(ans.begin(), ans.end()); | |
return ans; | |
} | |
// LCA | |
// ダブリングと根からの距離で頑張る | |
vector<vector<int>> parent; | |
map<int,int> dist; | |
int query(int x, int y){ | |
// xとyのLCAまでの距離を求めて、 | |
// x->LCA->y->xという閉路の長さを返す | |
if(dist[x] < dist[y]){ | |
return query(y,x); | |
} | |
int in = x; | |
int out = y; | |
// cerr << "before: x: " << x << " y: " << y << endl; | |
if(dist[x] != dist[y]){ | |
int up = dist[x] - dist[y]; | |
int log_up = log2(up); | |
// xのup個上に | |
for(ll k = log_up; k >= 0; k--){ | |
if((up>>k)&1){ | |
x = parent[k][x]; | |
} | |
} | |
// cerr << "after: x: " << x << " y: " << y << endl; | |
} | |
int lca; | |
if(x == y){ | |
lca = x; | |
} else { | |
int height = parent.size(); | |
for(int i = height -1; i >= 0; i--){ | |
if(parent[i][x] != parent[i][y]){ | |
x = parent[i][x]; | |
y = parent[i][y]; | |
} | |
} | |
// cerr << "LCA: " << parent[0][x] << endl; | |
lca = parent[0][x]; | |
} | |
return lca; | |
} | |
int main(){ | |
int N; | |
cin >> N; | |
vector<vector<int>> v(N); | |
int root; | |
for(int i = 0; i < N; i++){ | |
int tmp; | |
cin >> tmp; | |
if(tmp == -1){ | |
root = i; | |
} else { | |
tmp--; | |
v.at(i).push_back(tmp); | |
v.at(tmp).push_back(i); | |
} | |
} | |
// 0からの距離 | |
dist[root] = 0; | |
queue<int> q; | |
q.push(root); | |
int log_N = floor(log2(N)); | |
// cerr << N << " " << log_K << endl; | |
parent.assign(log_N+1, vector<int>(N)); | |
parent[0][root] = -1; | |
while(!q.empty()){ | |
int now = q.front(); | |
q.pop(); | |
for(int next: v.at(now)){ | |
if(dist.count(next) == 0){ | |
parent[0][next] = now; | |
dist[next] = dist[now] + 1; | |
q.push(next); | |
} | |
} | |
} | |
// ダブリング | |
for(int k = 0; k < log_N; k++){ | |
for(int i = 0; i < N; i++){ | |
if(parent[k][i] == -1){ | |
parent[k+1][i] = -1; | |
} else { | |
parent[k+1][i] = parent[k][parent[k][i]]; | |
} | |
} | |
} | |
int Q; | |
cin >> Q; | |
for(int i= 0; i < Q; i++){ | |
int tmp1,tmp2; | |
cin >> tmp1 >> tmp2; | |
tmp1--; | |
tmp2--; | |
int lca = query(tmp1,tmp2); | |
string ans; | |
if(tmp2 == lca){ | |
ans = "Yes"; | |
} else { | |
ans = "No"; | |
} | |
cout << ans << endl; | |
} | |
} | |
// 2次元累積和 | |
int main() { | |
// 入力: H × W のグリッド | |
int H, W; cin >> H >> W; | |
vector<vector<int> > a(H, vector<int>(W)); | |
for (int i = 0; i < H; ++i) for (int j = 0; j < W; ++j) cin >> a[i][j]; | |
// 二次元累積和 | |
vector<vector<int> > s(H+1, vector<int>(W+1, 0)); | |
for (int i = 0; i < H; ++i) | |
for (int j = 0; j < W; ++j) | |
s[i+1][j+1] = s[i][j+1] + s[i+1][j] - s[i][j] + a[i][j]; | |
// クエリ [x1, x2) × [y1, y2) の長方形区域の和 | |
int Q; cin >> Q; | |
for (int q = 0; q < Q; ++q) { | |
int x1, x2, y1, y2; | |
cin >> x1 >> x2 >> y1 >> y2; | |
cout << s[x2][y2] - s[x1][y2] - s[x2][y1] + s[x1][y1] << endl; | |
} | |
} | |
// セグメントツリー (区間和、区間最大値、区間最小値、区間最大公約数) | |
template<typename T> | |
T gcd(T a, T b) { | |
if(a < b) swap(a,b); | |
if(b == 0) return a; | |
return gcd(b, a % b); | |
} | |
typedef long long ll; | |
int const inf = INT_MAX / 2; | |
enum query_type { min_query, max_query, sum_query, gcd_query}; | |
template<class T> struct segtree { | |
int N; | |
vector<T> dat, sum; | |
function<T(T, T)> func; | |
T ngvalue; | |
void init(int n, function<T(T, T)> const& f, T ng) { | |
N = 1; | |
while(N < n) N <<= 1; | |
dat.assign(2 * N - 1, 0); | |
sum.assign(2 * N - 1, 0); | |
func = f; | |
ngvalue = ng; | |
} | |
segtree() = default; | |
segtree(int n, query_type qtype) { | |
if(qtype == min_query) { | |
init(n, [](T a, T b){return min(a, b);}, numeric_limits<T>::max()); | |
} | |
else if(qtype == max_query) { | |
init(n, [](T a, T b){return max(a, b);}, numeric_limits<T>::min()); | |
} | |
else if(qtype == sum_query) { | |
init(n, [](T a, T b){return a + b;}, 0); | |
} | |
else if(qtype == gcd_query) { | |
init(n, [](T a, T b){return gcd(a,b);}, 0); | |
} | |
else { | |
runtime_error("no matching query type"); | |
} | |
} | |
void add(int i, T x) { | |
add(i, i + 1, x); | |
} | |
void add(int a, int b, T x) { | |
add(a, b, x, 0, 0, N); | |
} | |
T add(int a, int b, T x, int k, int l, int r) { | |
if(b <= l || r <= a) return dat[k]; | |
if(a <= l && r <= b) { | |
sum[k] += x; | |
return dat[k] += x; | |
} | |
int m = (l + r) / 2; | |
return dat[k] = func(add(a, b, x, 2 * k + 1, l, m), add(a, b, x, 2 * k + 2, m, r)) + sum[k]; | |
} | |
T operator()(int a, int b) { | |
return query(a, b, 0, 0, N); | |
} | |
T query(int a, int b, int k, int l, int r) { | |
if(b <= l || r <= a) return ngvalue; | |
if(a <= l && r <= b) return dat[k]; | |
int m = (l + r) / 2; | |
return func(query(a, b, 2 * k + 1, l, m), query(a, b, 2 * k + 2, m, r)) + sum[k]; | |
} | |
}; | |
// segtree<int> st(N+2, sum_query); | |
// st(a,b) | |
// st.add(i,1) | |
// クラスカル法 | |
typedef pair<int,int> pii; | |
long long MOD = 1000000000 + 7; | |
struct UnionFind { | |
vector<int> data; | |
UnionFind(int size) : data(size, -1) { } | |
bool unionSet(int x, int y) { | |
x = root(x); y = root(y); | |
if (x != y) { | |
if (data[y] < data[x]) swap(x, y); | |
data[x] += data[y]; data[y] = x; | |
} | |
return x != y; | |
} | |
bool findSet(int x, int y) { | |
return root(x) == root(y); | |
} | |
int root(int x) { | |
return data[x] < 0 ? x : data[x] = root(data[x]); | |
} | |
int size(int x) { | |
return -data[root(x)]; | |
} | |
}; | |
int main(){ | |
cout << setprecision(10); | |
int N,M; cin >> N >> M; | |
vector<pair<int, pair<int,int>>> v(M); | |
for(int i = 0; i < M; i++){ | |
int x,y,z; cin >> x >> y >> z; | |
v[i] = make_pair(z, make_pair(x,y)); | |
} | |
sort(v.begin(), v.end()); | |
UnionFind tree(N); | |
vector<pair<int,int>> ans; | |
ll min_val = 0; | |
for(int i = 0; i < M; i++){ | |
ll weight = (ll)v[i].first; | |
int s = v[i].second.first; | |
int t = v[i].second.second; | |
if(tree.root(s) == tree.root(t)){ | |
continue; | |
} else { | |
min_val += weight; | |
tree.unionSet(s,t); | |
} | |
} | |
cout << min_val << endl; | |
} | |
// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment