Created
July 11, 2018 14:21
-
-
Save GoBigorGoHome/b838259b30c10846629a8e9067e87371 to your computer and use it in GitHub Desktop.
CC July 18 Subway ugly and bugy implementation
This file contains 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> | |
using namespace std; | |
#define pb push_back | |
#define eb emplace_back | |
#define all(x) x.begin(), x.end() | |
#define debug(x) cerr << #x <<": " << (x) << endl | |
//在每个函数的入口处执行一次,出口处执行一次。然后就可以快速得知是哪个地方段错误了 | |
#define DEBUG printf("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__) | |
#ifdef LOCAL | |
#define see(x) cout << #x << ": " << (x) << endl | |
#endif | |
#ifndef LOCAL | |
#define see(x) | |
#endif | |
#define RED "\033[31m" | |
#define RESET "\033[0m" | |
#define alert(x) cerr << RED << x << RESET << endl | |
#ifndef LOCAL | |
#define see(x) | |
#endif | |
#define rep(n) for(int _ = 0; _ != (n); ++_) | |
//#define rep(i, a, b) for(int i = (a); i <= (b); ++i) | |
#define Rng(i, n) for(int i = 0; i != (n); ++i) | |
#define rng(i, a, b) for(int i = (a); i < (b); ++i) | |
#define RNG(i, a) for(auto &i: (a)) | |
#define dwn(i, r, l) for(int i = (r); i>=(l); i--) | |
namespace std { | |
template<class T> | |
T begin(std::pair<T, T> p) | |
{ | |
return p.first; | |
} | |
template<class T> | |
T end(std::pair<T, T> p) | |
{ | |
return p.second; | |
} | |
} | |
#if __cplusplus < 201402L | |
template<class Iterator> | |
std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it) | |
{ | |
return std::reverse_iterator<Iterator>(it); | |
} | |
#endif | |
template<class Range> | |
std::pair<std::reverse_iterator<decltype(begin(std::declval<Range>()))>, std::reverse_iterator<decltype(begin(std::declval<Range>()))>> make_reverse_range(Range &&r) | |
{ | |
return std::make_pair(make_reverse_iterator(::begin(r)), make_reverse_iterator(::end(r))); | |
} | |
#define RRNG(x, cont) for (auto &x: make_reverse_range(cont)) | |
template<class T> int sign(const T &a) { return a == 0 ? 0 : a > 0 ? 1 : -1; } | |
template<class T> inline T min(T a, T b, T c){return min(min(a, b), c);} | |
template<class T> inline T max(T a, T b, T c){return max(max(a, b), c);} | |
template<class T> void Min(T &a, const T &b){ a = min(a, b); } | |
template<class T> void Max(T &a, const T &b){ a = max(a, b); } | |
template<typename T> void println(const T &t) { cout << t << '\n'; } | |
template<typename T, typename ...Args> void println(const T &t, const Args &...rest) { cout << t << ' '; println(rest...); } | |
template<typename T> void print(const T &t) { cout << t << ' '; } | |
template<typename T, typename ...Args> void print(const T &t, const Args &...rest) { cout << t; print(rest...); } | |
// this overload is chosen when there's only one argument | |
template<class T> void scan(T &t) { cin >> t; } | |
template<class T, class ...Args> void scan(T &a, Args &...rest) { cin >> a; scan(rest...); } | |
using ll = long long; | |
using ull = unsigned long long; | |
using vec = vector<ll>; | |
using mat = vector<vec>; | |
using pii = pair<int, int>; | |
using pdd = pair<double, double>; | |
using pip = pair<int, pii>; | |
using szt = size_t; | |
using vi = vector<int>; | |
using vl = vector<ll>; | |
using vb = vector<bool>; | |
using vpii = vector<pii>; | |
using vvi = vector<vi>; | |
using pli = pair<ll,int>; | |
int cas; | |
const double pi = acos(-1); | |
ll mod = 1e9 + 7; | |
template<class T> | |
inline void add_mod(T &a, const T &b) { | |
a += b; | |
if (a >= mod) a -= mod; | |
} | |
template<class T> | |
void sub_mod(T &a, const T &b){ | |
a -= b; | |
if (a < 0) a += mod; | |
} | |
auto bo=[](int x){ //二进制输出 | |
bitset<5> a(x); | |
cout << a << endl; | |
}; | |
mat operator*(const mat &a, const mat &b) { | |
mat c(a.size(), vec(b[0].size())); | |
for (int i = 0; i < a.size(); i++) { | |
for (int j = 0; j < a[0].size(); j++) { | |
if (a[i][j]) { // optimization for sparse matrix | |
for (int k = 0; k < b[0].size(); k++) { | |
add_mod(c[i][k], a[i][j] * b[j][k] % mod); | |
} | |
} | |
} | |
} | |
return c; | |
} | |
vec operator*(const mat &a, const vec &b) { | |
vec c(a.size()); | |
for (int i = 0; i < a.size(); i++) { | |
for (int j = 0; j < a[0].size(); j++) { | |
add_mod(c[i], a[i][j] * b[j] % mod); | |
} | |
} | |
return c; | |
} | |
mat pow(mat a, ull n) { | |
mat res(a.size(), vec(a[0].size())); | |
for (int i = 0; i < a.size(); i++) { | |
res[i][i] = 1; | |
} | |
while (n) { | |
if (n & 1) { | |
res = res * a; | |
} | |
a = a * a; | |
n >>= 1; | |
} | |
return res; | |
} | |
std::ostream& operator<<(std::ostream& os, __int128 T) { | |
if (T<0) os<<"-"; | |
if (T>=10 ) os<<T/10; | |
if (T<=-10) os<<(-(T/10)); | |
return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ; | |
} | |
__int128 LPOW(__int128 x, ll n) { | |
__int128 res = 1; | |
for (; n; n /= 2, x *= x, x %= mod) { | |
if (n & 1) { | |
res *= x; | |
res %= mod; | |
} | |
} | |
return res; | |
} | |
ll POW(ll x, ll n){ | |
ll res = 1; | |
for (; n; n /= 2, x *= x, x %= mod) { | |
if (n & 1) { | |
res *= x; | |
res %= mod; | |
} | |
} | |
return res; | |
} | |
ll INV(ll x) { | |
return POW(x, mod - 2); | |
} | |
ll inv(ll x){ | |
// see(x); | |
return x == 1? 1: (mod - mod/x * inv(mod%x) % mod); | |
} | |
// 2D rotation | |
void rotate(double &x, double &y, double theta) { | |
double tx = cos(theta) * x - sin(theta) * y; | |
double ty = sin(theta) * x + cos(theta) * y; | |
x = tx, y = ty; | |
} | |
namespace bit { | |
const int BIT_N = 1e5 + 5; | |
int bit[BIT_N]; | |
int sum(int x) { | |
int res = 0; | |
while (x) { | |
res += bit[x]; | |
x -= x & -x; | |
} | |
return res; | |
} | |
int sum(int l, int r) { | |
if (l > r) return 0; | |
return sum(r) - sum(l - 1); | |
} | |
void add(int x, int v, int n) { | |
while (x <= n) { | |
bit[x] += v; | |
x += x & -x; | |
} | |
} | |
} | |
namespace util{ | |
int len(ll x){return snprintf(nullptr, 0, "%lld", x);} | |
vi get_d(ll x){ | |
vi res; | |
while(x) { | |
res.pb(x%10); | |
x /= 10; | |
} | |
reverse(all(res)); | |
return res; | |
} | |
template <class T> T parity(const T &a){ | |
return a & 1; | |
} | |
template <class T> | |
void out (const vector<T> &a){ | |
std::copy(a.begin(), a.end(), std::ostream_iterator<T>(std::cout, ", ")); | |
cout << endl; | |
}; | |
} | |
using namespace util; | |
// #include <ext/pb_ds/priority_queue.hpp> | |
// typedef __gnu_pbds :: priority_queue<pip, less<pip>, __gnu_pbds::thin_heap_tag > Heap; | |
// Heap h; | |
// Heap::point_iterator pos[N][N]; | |
const ll LINF = LLONG_MAX/10; | |
const int INF = INT_MAX/10; | |
const int M = 3000 + 5; | |
const int N = 5e5+5; | |
using wg = vector<vpii>; //weighted graph | |
int main() { | |
// Single Cut of Failure taught me | |
cout << std::fixed; // 使所有实数(默认)输出6位小数,即使实际小数位数多于6位。 | |
cout << setprecision(10); | |
ios::sync_with_stdio(false); | |
cin.tie(nullptr); | |
#ifdef LOCAL | |
freopen("main.in", "r", stdin); | |
// freopen("main.out", "w", stdout); | |
#endif | |
int n, m; | |
scan(n, m); | |
wg g(n+1); | |
vector<set<int>> color(n); | |
int cnt = 0; | |
map<pii,int> id; | |
rep(m){ | |
int u, v, w; | |
scan(u, v, w); | |
if(u > v) swap(u, v); | |
auto iter = id.find({u,v}); | |
if(iter != id.end()){ | |
color[iter->second].insert(w); | |
} | |
else{ | |
++cnt; | |
color[cnt].insert(w); | |
g[u].eb(v, cnt); | |
g[v].eb(u, cnt); | |
id[{u,v}] = cnt; | |
} | |
} | |
int q; | |
scan(q); | |
wg Q(n+1); | |
rng(i, 0, q){ | |
int u, v; | |
scan(u, v); | |
Q[u].eb(v, i); | |
} | |
vi size(n+1); | |
vb used(n+1); | |
function<pii(int,int)> centroid; | |
centroid = [¢roid, &size, &used, &g, n](int u, int f){ | |
size[u]=1; | |
int ma=0; | |
pair<int,int> res={INT_MAX, 0}; | |
for(auto e: g[u]){ | |
int v=e.first; | |
if(v!=f && !used[v]){ | |
res=min(res, centroid(v, u)); | |
size[u]+=size[v]; | |
ma=max(ma, size[v]); | |
} | |
} | |
ma=max(ma, n-size[u]); | |
res=min(res, {ma, u}); | |
return res; | |
}; | |
// 计算每个点到根节点的最长路的长度 | |
function<void(int,int,int,int)> dfs; | |
vector<set<int>> first_edge(n+1); // 最长路的首边颜色集合 | |
vi last_edge(n+1); //到根节点的最长路的末边颜色是否唯一 | |
vi d(n+1); // 到根节点的最长路的长度。 | |
vi fa(n+1); // 记录父亲 | |
vi no(n+1); // no[u]:u与父亲之间的边的编号 | |
// 查看第一个top点到根的最长路的末边颜色是否唯一。 | |
auto check_unique = [&fa, &no, &color](int u, int c){ | |
// if(color[no[fa[u]]].size() <= 1) return c; | |
while(color[no[fa[u]]].size() >= 2){ | |
int i = no[fa[u]]; | |
assert(color[i].size() >= 2); | |
if(color[i].size() > 2 || (color[i].size() == 2 && color[i].find(c) == color[i].end())){ | |
return 0; | |
} | |
c = c == *color[i].begin() ? *color[i].rbegin() : *color[i].begin(); | |
u = fa[u]; | |
} | |
return c; | |
}; | |
//再加上LCA | |
vpii label(n+1); | |
int root; | |
dfs = [&](int u, int f, int top, int num) { //num:对子树的编号 | |
fa[u] = f; | |
label[u].first = root; | |
RNG(e, g[u]) { | |
int v = e.first; | |
if(v == f || used[v]) continue; | |
auto &s = color[e.second]; | |
no[v] = e.second; | |
// 计算最长路 | |
if(u == root) { | |
first_edge[v] = s; | |
d[v] = 1; | |
num = v; | |
} | |
else { | |
auto &t = first_edge[u]; | |
if(t.size() > 1) { | |
first_edge[v] = s; | |
d[v] = d[u] + 1; | |
} | |
else { | |
int tmp = *t.begin(); | |
if(s.size() == 1 && *s.begin() == tmp) { | |
d[v] = d[u]; | |
first_edge[v] = s; | |
} | |
else { | |
d[v] = d[u] + 1; | |
first_edge[v] = s; | |
first_edge[v].erase(tmp); | |
} | |
} | |
} | |
// 末边状态 | |
if(s.size() == 1 && top == -1) { | |
top = check_unique(u, *s.begin()); | |
} | |
if(top != -1){ | |
last_edge[v] = top; | |
} | |
label[v].second = num; | |
dfs(v, u, top, num); | |
} | |
}; | |
vi ans(q); | |
function<void(int,int)> calc; | |
calc = [&](int u, int f){ | |
RNG(x, Q[u]){ | |
int v = x.first, i = x.second; | |
if(v == u || label[v].first != root) continue; | |
if(u==root){ | |
ans[i] = d[v]; | |
} | |
else if(v==root){ | |
ans[i] = d[u]; | |
} | |
else if(label[u].second != label[v].second){ | |
if(last_edge[v] == 0 || last_edge[u] == 0){ | |
ans[i] = d[u] + d[v]; | |
} | |
else{ | |
ans[i] = d[u] + d[v] - (last_edge[u] == last_edge[v]); | |
} | |
} | |
} | |
RNG(e, g[u]){ | |
int &v = e.first; | |
if(used[v] || v == f) continue; | |
} | |
}; | |
function<void(int)> DC; | |
DC = [&](int u){ | |
root = centroid(u, u).second; | |
dfs(root, 0, -1, 0); | |
}; | |
#ifdef LOCAL | |
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n"; | |
#endif | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment