Competitive Programming
Author: Gino
Credit: WiwiHorz
//#define BlackMagic
#ifdef BlackMagic
#include <bits/extc++.h>
using namespace __gnu_pbds;
#endif
#include <bits/stdc++.h>
/* ----------------------------------------------- */
#define elpsycongroo ios_base::sync_with_stdio(false); cin.tie(0);
#define REP(i, n) for (int i = 0; i < n; i++)
#define FOR(i, a, b, c) for (int i = a; i < b; i += c)
#define Each(i, v) for (auto& i : v)
#define ariter(_a, _n) _a, _a+_n
#define iter(a) a.begin(), a.end()
#define mp(a, b) make_pair(a, b)
#define F first
#define S second
#define pb(a) push_back(a)
#define eb(a) emplace_back(a)
#define dbg(a, b) cout << "var " << a << " -> " << b << '\n';
#define dbg_itv(l, r, val) cout << "### (" << l << ", " << r << ") -> " << val << '\n';
#define flag(_a) cout << "Still alive at flag " << _a << '\n';
#define printv(_a) for (auto& _i : _a) cout << _i << ' '; cout << '\n';
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 1e5 + 1;
const int INF = 2147483647;
const ll LLINF = 1e18;
const int MOD = 1e9 + 7;
ll len(ll L, ll R) {
return R-L+1;
}
/* ------------------------------------------- */
int main() {
elpsycongroo
//
return 0;
}
/* test case
*/
// map
tree<int, int, less<>, rb_tree_tag, tree_order_statistics_node_update> tr;
tr.order_of_key(123);
tr.find_by_order(123);
// set
tree<int, null_type, less<>, rb_tree_tag, tree_order_statistics_node_update> tr;
tr.order_of_key(123);
tr.find_by_order(123);
__gnu_pbds::priority_queue<int, less<int> > big_q; // Big First
__gnu_pbds::priority_queue<int, greater<int> > small_q; // Small First
q1.join(q2); // join
pll operator+(pll a, pll b) {
return mp(a.F + b.F, a.S + b.S);
}
pll operator-(pll a, pll b) {
return mp(a.F - b.F, a.S - b.S);
}
pll mul(pll a, ll b) {
return mp(a.F * b, a.S * b);
}
ll operator*(pll a, pll b) {
return a.F * b.F + a.S * b.S;
}
ll operator^(pll a, pll b) {
return a.F * b.S - a.S * b.F;
}
ll dis(pll a, pll b) {
ll dx = abs(a.F-b.F), dy = abs(a.S-b.S);
return dx * dx + dy * dy;
}
ll EulerDis(pll a, pll b) {
return abs(a.F-b.F) + abs(a.S-b.S);
}
int quad(pll a) {
// origin : 1st
// x+ : 1st
// y+ : 2nd
// x- : 3rd
// y- : 4th
int x = a.F, y = a.S;
if (x == 0 && y == 0) return 1;
if (x == 0) return (y > 0 ? 2 : 4);
if (y == 0) return (x > 0 ? 1 : 3);
if (y > 0) return (x > 0 ? 1 : 2);
else return (x > 0 ? 4 : 3);
}
vector<pll> E;
bool CmpByAngle(pll a, pll b) {
int qa = quad(a), qb = quad(b);
if (qa == qb) {
ll crs = a^b;
if (crs == 0) return EulerDis(a, mp(0, 0)) < EulerDis(b, mp(0, 0));
return crs > 0;
}
return qa < qb;
}
sort(iter(E), CmpByAngle);
int ori(ll cross) {
// vector a x b
// 1: a to b = counterclockwise
// 0: a & b in the same direction
// -1: a to b = clockwise
return (cross > 0) - (cross < 0);
}
int in_segment(pll a1, pll a2, pll b) {
return (((a1-b)^(a2-b)) == 0 && (a1-b)*(a2-b)<=0);
}
int banana(pll p1, pll p2, pll q1, pll q2) {
if (in_segment(p1, p2, q1) || in_segment(p1, p2, q2) ||
in_segment(q1, q2, p1) || in_segment(q1, q2, p2)) {
return 1;
}
return (ori((p2-q1) ^ (p1-q1)) * ori((p2-q2) ^ (p1-q2)) == -1 &&
ori((q2-p1) ^ (q1-p1)) * ori((q2-p2) ^ (q1-p2)) == -1);
}
int inPolygon(vector<pll>& E , pll p){
for(int i = 0; i < E.size(); i++) {
if(((p-E[i])^(E[posmd(i-1, E.size())]-E[i])) * ((p-E[i])^(E[posmd(i+1, E.size())]-E[i])) > 0)
return false;
}
return true;
}
vector<pll> getConvexHull(vector<pll>& E) {
int n = E.size();
sort(iter(E));
vector<pll> hull;
hull.reserve(n);
for(int i = 0; i < 2; i++) {
int t = hull.size();
for(auto& pnt : E){
while(hull.size() - t >= 2 &&
(back - hull[hull.size()-2])^(pnt - hull[hull.size()-2]) <= 0) {
// <= 0: not include the node on hull's edge
// < 0: included
hull.pop_back();
}
hull.pb(pnt);
}
hull.pop_back();
reverse(iter(E));
}
return hull;
}
ll area(vector<pll>& p){
T ans = 0;
for(int i = 0; i < p.size(); i++) {
ans += p[i] ^ [(i + 1) % p.size()];
}
return ans / 2;
}
#define x first
#define y second
inline ll dis(pll& a, pll& b) {
ll dx = a.x - b.x;
ll dy = a.y - b.y;
return dx * dx + dy * dy;
}
int N;
ll ans = LLINF;
vector<pll> p, tmp;
void init() {
cin >> N;
p.resize(N);
}
void dfs(int l, int r) {
int n = len(l, r);
// small case
if (n <= 20) {
FOR(i, l, r, 1) {
FOR(j, i+1, r+1, 1) {
ans = min(ans, dis(p[i], p[j]));
}
}
return;
}
// divide (using x coordinate of median point)
int mid = (l+r) / 2;
int ml = mid, mr = mid;
ll midx = p[mid].x;
while (l <= ml && p[ml].x == midx) ml--;
while (mr <= r && p[mr].x == midx) mr++;
if (l <= ml) dfs(l, ml);
if (mr <= r) dfs(mr, r);
// conquer
ll d = sqrt(ans)+1;
tmp.clear();
for (int i = mid; i >= l; i--) {
if (abs(p[i].x - midx) <= d) tmp.eb(p[i]);
else break;
}
for (int i = mid+1; i <= r; i++) {
if (abs(p[i].x - midx) <= d) tmp.eb(p[i]);
else break;
}
sort(iter(tmp), [&](pll& a, pll& b) {
return a.y < b.y;
});
int nt = (int)tmp.size();
REP(i, nt) {
// considering next 3 points is enough
for (int j = i+1, cnt = 0; j < nt && cnt < 3; j++, cnt++) {
ans = min(ans, dis(tmp[i], tmp[j]));
}
}
return;
}
int main() {
WiwiHorz
init();
Each(i, p) cin >> i.x >> i.y;
sort(iter(p));
dfs(0, N-1);
cout << ans << endl;
return 0;
}
ll gcd(ll a, ll b) {
if (b == 0) return a;
return gcd(b, a%b);
}
__gcd(a, b);
ll GCD;
pll extgcd(ll a, ll b) {
if (b == 0) {
GCD = a;
return pll{1, 0};
}
pll ans = extgcd(b, a % b);
return pll{ans.S, ans.F - a/b * ans.S};
}
pll bezout(ll a, ll b, ll c) {
bool negx = (a < 0), negy = (b < 0);
pll ans = extgcd(abs(a), abs(b));
if (c % GCD != 0) return pll{-LLINF, -LLINF};
return pll{ans.F * c/GCD * (negx ? -1 : 1),
ans.S * c/GCD * (negy ? -1 : 1)};
}
ll inv(ll a, ll p) {
if (p == 1) return -1;
pll ans = bezout(a % p, -p, 1);
if (ans == pll{-LLINF, -LLINF}) return -1;
return (ans.F % p + p) % p;
}
vector <int> lpf;
vector <int> prime;
void seive(int n) {
lpf.resize(n+1, 1)
prime.clear();
for(int i = 2; i <= n; i++){
if(lpf[i] == 1){
lpf[i] = i;
prime.emplace_back(i);
}
for(int j : prime){
if(i * j > n) break;
lpf[i * j] = j;
if(j == lpf[i]) break;
}
}
}
vector<pii> pf;
void decompose(ll x) {
while(x > 1){
int d = lpf[x];
pf.emplace_back(mp(d, 0));
while(x % d == 0){
pf.back().S++;
x /= d;
}
}
}
void dijk(int s) {
priority_queue<pll, vector<pll>, greater<pll> > pq;
fill(ariter(dis, maxn), INF);
dis[s] = 0;
pq.push(mp(0, s));
while (!pq.empty()) {
pll u = pq.top();
pq.pop();
if (dis[u.S] != u.F) continue;
for (auto& e : G[u.S]) {
if (dis[e.S] > dis[u.S] + e.F) {
dis[e.S] = dis[u.S] + e.F;
pq.push(mp(dis[e.S], e.S));
}
}
}
}
int n, m, p[maxn], rk[maxn];
vector<pil> E; // u, v, w
bool cmp(pil a, pil b) {
return a.S < b.S;
}
int find(int x) {
if (x == p[x]) return x;
return p[x] = find(p[x]);
}
void Union(int x, int y) {
int bx = find(x), by = find(y);
if (rk[bx] < rk[by]) {
p[bx] = by;
} else {
p[by] = bx;
if (rk[bx] == rk[by])
rk[bx]++;
}
}
int main() {
Optimize
// n: |V|, m: |E|
cin >> n >> m;
while (m--) {
int u, v; ll w;
cin >> u >> v >> w;
E.emplace_back(mp(mp(u, v), w));
}
for (int i = 0; i <= n; i++) {
rk[i] = 1;
p[i] = i;
}
ll ans = 0;
sort(E.begin(), E.end(), cmp);
for (auto& i : E) {
if (find(i.F.F) != find(i.F.S)) {
ans += i.S;
Union(i.F.F, i.F.S);
}
}
cout << ans << '\n';
return 0;
}
int n; // sizeof BIT
ll bit[maxn];
ll lb(ll x) {return x & (-x);}
void modify(int x, ll val) {
for (; x <= n; x += lb(x)) {
bit[x] += val;
}
}
ll qry(int x) {
ll sum = 0;
for (;x; x -= lb(x)) {
sum += bit[x];
}
return sum;
}
vector<int> arr;
int spt[maxn][20];
int n, q;
void build() {
REP(i, n) spt[i][0] = arr[i];
for (int j = 1; j < 20; j++) {
for (int i = 0; i+(1<<j)-1 < n; i++) {
spt[i][j] = max(spt[i][j-1], spt[i+(1<<(j-1))][j-1]);
}
}
}
int hb(int x) {
for (int j = 19; j >= 0; j--) {
if (x & (1<<j)) return j;
}
}
int qry(int l, int r) {
int b = hb(len(l, r));
return max(spt[l][b], spt[r-(1<<b)+1][b]);
}
struct node {
// define your value and tag here
}
void pull(int cl, int cr, int idx) {
// Update the answer
// No other tricks, its easy
}
void push(int l, int r, int idx, int cl, int cr, int mid) {
/* Important Concept:
* Every tag records their CHILDREN need to be modify
* EXCLUDING ITSELF!!!
* Self has already been modified when assigned tag!
*
* Special Case: Leaf Node (no children)
* Change first, Addition second
*
* 1. Update children's value
* 2. Assign the same tag to children
* 3. Reset self's tag
*/
}
void build(int l, int r, int idx) {
/* Special Case: Leaf Node
* Build LEFT
* Build RIGHT
* if (NOT LEAF) pull() // Because pull() needs parameters of children
*/
}
void modify(int ql, int qr, int val, int l, int r, int idx) {
/* if (current itv not in query) return;
* if (current itv all in query) {
* Update value
* Put tag
* return;
* }
* PUSH()
* Modify LEFT
* Modify RIGHT
* if (NOT LEAF) pull()
*/
}
int query(int ql, int qr, int val, int l, int r, int idx) {
/* if (current itv not in query) return an unimportant value
* if (current itv all in query) return self's value
* PUSH()
* Ask LEFT
* Ask RIGHT
* Decide which to return
*/
}
struct node {
ll mx, sum;
ll add, mod;
node(): mx(0), sum(0), add(0), mod(0) {}
};
typedef struct node node;
node st[maxn*4];
vector<ll> arr;
void pull(int cl, int cr, int idx) {
st[idx].mx = max(st[cl].mx, st[cr].mx);
st[idx].sum = st[cl].sum + st[cr].sum;
}
void push(int l, int r, int idx, int cl, int cr, int mid) {
if (l == r) {
st[idx].mod = 0;
st[idx].add = 0;
return;
}
ll md = st[idx].mod, ad = st[idx].add;
if (md) {
st[cl].sum = md * len(l, mid);
st[cr].sum = md * len(mid+1, r);
st[cl].mx = st[cr].mx = md;
st[cl].mod = st[cr].mod = md;
st[cl].add = st[cr].add = 0;
st[idx].mod = 0;
}
if (ad) {
st[cl].sum += ad * len(l, mid);
st[cr].sum += ad * len(mid+1, r);
st[cl].mx += ad;
st[cr].mx += ad;
st[cl].add += ad;
st[cr].add += ad;
st[idx].add = 0;
}
}
void build(int l, int r, int idx) {
if (l == r) {
st[idx].sum = arr[l];
st[idx].mx = arr[l];
return;
}
int mid = (l+r) >> 1, cl = (idx<<1), cr = (idx<<1) + 1;
build(l, mid, cl);
build(mid+1, r, cr);
if (l != r) pull(cl, cr, idx);
}
void addval(int ql, int qr, ll val, int l, int r, int idx) {
if (qr < l || r < ql) return;
if (ql <= l && r <= qr) {
st[idx].mx += val;
st[idx].sum += val * len(l, r);
st[idx].add += val;
return;
}
int mid = (l+r)>>1, cl = (idx<<1), cr = (idx<<1) + 1;
push(l, r, idx, cl, cr, mid);
addval(ql, qr, val, l, mid, cl);
addval(ql, qr, val, mid+1, r, cr);
if (l != r) pull(cl, cr, idx);
}
void modify(int ql, int qr, ll val, int l, int r, int idx) {
if (qr < l || r < ql) return;
if (ql <= l && r <= qr) {
st[idx].mx = val;
st[idx].sum = val * len(l, r);
st[idx].add = 0;
st[idx].mod = val;
return;
}
int mid = (l+r)>>1, cl = (idx<<1), cr = (idx<<1) + 1;
push(l, r, idx, cl, cr, mid);
modify(ql, qr, val, l, mid, cl);
modify(ql, qr, val, mid+1, r, cr);
if (l != r) pull(cl, cr, idx);
}
ll query(int ql, int qr, int type, int l, int r, int idx) {
/* type:
* 3 = sum
* 4 = max
*/
if (qr < l || r < ql) return 0;
if (ql <= l && r <= qr) {
return (type == 3 ? st[idx].sum : st[idx].mx);
}
int mid = (l+r)>>1, cl = (idx<<1), cr = (idx<<1) + 1;
push(l, r, idx, cl, cr, mid);
if (type == 3) {
return (query(ql, qr, type, l, mid, cl) +
query(ql, qr, type, mid+1, r, cr));
} else {
return max(query(ql, qr, type, l, mid, cl),
query(ql, qr, type, mid+1, r, cr));
}
}
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<int> dis(1, 100);
cout << dis(rnd) << "\n";
/* Steps to build suffix array
* 1. Base Case: One letter
* Do AnySort() -> store in buc[0]
* Fill SA and Rank
*
* 2. Repeat O(log(n)) times
* Fill buc[0] with last result
* Do RadixSort()
* Fill SA and Rank
*
* Conditions for ending in advance:
* if every element is distinct (Rank[i] all diff)
* // just end process
*
* Tip: Radix Sort
* Repeat twice
* Count
* Reset bucket (build pos array)
* Fill element into new bucket
*/
// For Building Suffix Array and LCP Array
int n;
string s;
vector<int> suf, lcp, rk;
// For Radix Sort
vector<int> cnt, pos;
vector<pair<pii, int> > buc[2]; // 0: result, 1: temp
void init() {
n = (int)s.size();
suf.resize(n);
rk.resize(n);
cnt.resize(n);
pos.resize(n);
Each(i, buc) i.resize(n);
}
void radix_sort() {
REP(t, 2) {
fill(iter(cnt), 0);
Each(i, buc[t]) cnt[ (t ? i.F.F : i.F.S) ]++;
REP(i, n) {
pos[i] = (!i ? 0 : pos[i-1] + cnt[i-1]);
}
Each(i, buc[t]) {
buc[t^1][pos[ (t ? i.F.F : i.F.S) ]++] = i;
}
}
}
bool fill_suf() {
bool end = true;
REP(i, n) suf[i] = buc[0][i].S;
rk[suf[0]] = 0;
FOR(i, 1, n, 1) {
int dif = (buc[0][i].F != buc[0][i-1].F);
end &= dif;
rk[suf[i]] = rk[suf[i-1]] + dif;
}
return end;
}
void sa() {
s += (char)30;
init();
REP(i, n) buc[0][i] = mp(mp(s[i], s[i]), i);
sort(iter(buc[0]));
if (fill_suf()) return;
for (int k = 0; (1<<k) < n; k++) {
REP(i, n) {
buc[0][i] = mp(mp(rk[i], rk[(i + (1<<k)) % n]), i);
}
radix_sort();
if (fill_suf()) return;
}
}
// lcp[i] = lcp(rank_i, rank_(i-1))
// lcp[0] = 0
void LCP() {
int k = 0;
REP(i, n-1) {
int pi = rk[i];
int j = suf[pi-1];
while (s[i+k] == s[j+k]) k++;
lcp[pi] = k;
k = max(k-1, 0);
}
}
int main() {
elpsycongroo
cin >> s;
sa();
REP(i, n) cout << suf[i] << ' ';
cout << '\n';
REP(i, n) cout << lcp[i] << ' ';
cout << '\n';
return 0;
}
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up