A B C D E F G H I J K L M
O O O O     $\varnothing$     $\varnothing$  $\varnothing$  $\varnothing$   $\varnothing$

[A. Relic Discovery]

签到

#include <bits/stdc++.h>

int n;

int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
int ans = ;
for (int i = ; i < n; i++) {
int a, b;
scanf("%d%d", &a, &b);
ans += a * b;
}
printf("%d\n", ans);
}
return ;
}

[B. Pocket Cube]

判断所有情况,写丑了。

#include <bits/stdc++.h>

const int N = ;
int a[N], b[N];
const int n = ; bool check() {
for (int i = ; i <= ; i++) {
int j = (i - ) * + ;
int num = b[j];
for (int cnt = ; cnt < ; j++, cnt++)
if (b[j] != num) return false;
}
return true;
} int main() {
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
for (int i = ; i <= ; i++)
scanf("%d", a + i);
memcpy(b, a, sizeof(a));
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(a));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
memcpy(b, a, sizeof(b));
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
b[] = a[]; b[] = a[];
if (check()) {
puts("YES");
continue;
}
puts("NO");
}
return ;
}

[C. Pocky]

当 $n > d$ 时,$f(n) = \dfrac{\int_{d} ^{n} f(x)dx}{n} + 1$
当 $n \leq d$ 时,$f(n) = 0$
解得 $f(n) = ln(\dfrac{n}{d}) + 1$

#include<bits/stdc++.h>

const double eps = 1e-;

int dcmp(double x) {
if (fabs(x) < eps) return ;
return x < ? - : ;
} int main() {
int T;
scanf("%d", &T);
while (T--) {
double a, b;
scanf("%lf%lf", &a, &b);
if (dcmp(a - b) <= ) {
puts("0.000000");
continue;
}
double ans = log(a) - log(b) + 1.0;
printf("%.6f\n", ans);
}
return ;
}

[D. Lucky Coins]

每种硬币都是独立的。那么求出第 $i$ 种硬币在第 $j$ 轮之前都被拿掉的概率 $die[i][j] = (1 - p_{i} ^ j)^{cnt_i}$。$alive[i][j] = 1 - die[i][j]$ 表示第 $i$ 种硬币在第 $j$ 轮还存活的概率。
对于第 $i$ 种硬币的答案就是 $\sum_{step} (alive[i][step] - alive[i][step + 1]) * \prod_{j!=i}die[j][step]$。

#include <bits/stdc++.h>

const int N = ;
const int step = ; double qp(double a, int n) {
double ans = ;
while (n) {
if (n & ) ans *= a;
a *= a;
n >>= ;
}
return ans;
} double alive[N][step], die[N][step], p[N];
int cnt[N], n; void init(int index) {
double pp = p[index];
for (int i = ; i < step; i++) {
die[index][i] = qp( - pp, cnt[index]);
alive[index][i] = - die[index][i];
pp *= p[index];
}
} double solve(int index) {
double ans = ;
for (int i = ; i < step - ; i++) {
double temp = alive[index][i] - alive[index][i + ];
for (int j = ; j <= n; j++) {
if (j == index) continue;
temp *= die[j][i];
}
ans += temp;
}
return ans;
} int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = ; i <= n; i++) {
scanf("%d%lf", cnt + i, p + i);
init(i);
}
if (n == ) {
puts("1.000000");
continue;
}
for (int i = ; i <= n; i++)
printf("%.6f%c", solve(i), " \n"[i == n]);
}
return ;
}

[G. Coding Contest]

求出最小的崩溃概率,即求最大的未崩溃概率。

转化成二分图。人多于食物的为 $X$,人少于食物的为 $Y$。

概率取对数,跑费用流即可。注意判最短路时的精度问题。

#include <bits/stdc++.h>

const int N =  + ;
const int M = 2e4 + ;
const double inf = 1e12;
const int INF = 0x3f3f3f3f; struct E {
int v, ne, f;
double c;
} e[M];
int head[N], cnt;
double dis[N];
int path[N], n, m;
bool inq[N]; inline void add(int u, int v, int f, double c) {
e[cnt].v = v; e[cnt].f = f; e[cnt].c = c; e[cnt].ne = head[u]; head[u] = cnt++;
e[cnt].v = u; e[cnt].f = ; e[cnt].c = -c; e[cnt].ne = head[v]; head[v] = cnt++;
} const double eps = 1e-; int dcmp(double x) {
if (fabs(x) < eps) return ;
return x < ? - : ;
} bool spfa(int s, int t) {
for (int i = ; i <= t; i++)
dis[i] = inf, inq[i] = , path[i] = -;
dis[s] = ;
inq[s] = ;
std::queue<int> que;
que.push(s);
while (!que.empty()) {
int u = que.front(); que.pop();
inq[u] = ;
for (int i = head[u]; ~i; i = e[i].ne) {
int v = e[i].v; double c = e[i].c;
if (e[i].f && dcmp(dis[v] - dis[u] - c) > ) {
dis[v] = dis[u] + c;
path[v] = i;
if (!inq[v]) {
inq[v] = ;
que.push(v);
}
}
}
}
return dis[t] != inf;
} double mcf(int s, int t) {
double ans = ;
while (spfa(s, t)) {
int x = INF;
for (int i = path[t]; ~i; i = path[e[i ^ ].v]) x = std::min(x, e[i].f);
ans += dis[t] * x;
for (int i = path[t]; ~i; i = path[e[i ^ ].v]) e[i].f -= x, e[i ^ ].f += x;
}
return ans;
} int main() {
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
memset(head, -, sizeof(head));
cnt = ;
scanf("%d%d", &n, &m);
int s = , t = n + ;
for (int i = ; i <= n; i++) {
int S, B;
scanf("%d%d", &S ,&B);
if (S > B) add(s, i, S - B, );
else if(S<B)add(i, t, B - S, );
}
for (int i = ; i <= m; i++) {
int u, v, c; double p;
scanf("%d%d%d%lf", &u, &v, &c, &p);
add(u, v, , );
if (c > ) add(u, v, c - , -log(1.0 - p));
}
printf("%.2f\n", 1.0 - exp(-mcf(s, t)));
}
return ;
}

[J. Cliques] 

图是若干团的并的充要条件是不存在一个三元组其中只有两条边。维护只有两条边的三元组,每一步枚举要删去哪条边或者加上哪条边,当没有这样的三元组时为一个合法的方案。搜十步即可。

删去一条边或加上一条边最多影响 $n$ 个三元组,暴力修改即可。

维护三元组可以用像前向星的方法,加直接在末端添加,删把末端的加到要删的位置上即可。

复杂度 $O(n3^{10})$

#include <cstdio>
#include <algorithm>
#include <cstring> const int N = ;
int mp[N][N], n; struct SET {
int tol, edge[N * N * N], head[N * N * N];
void insert(int x) {
edge[++tol] = x;
head[x] = tol;
}
void erase(int x) {
head[edge[tol]] = head[x];
edge[head[x]] = edge[tol];
tol--;
}
bool empty() {
return tol == ;
}
void clear() {
tol = ;
}
} st; int ans; inline int cal(int i, int j, int k) {
int a[] = {i, j, k};
std::sort(a, a + );
return (a[] - ) * n * n + (a[] - ) * n + (a[] - );
} inline void add(int i, int j, int k) {
if (mp[i][j] + mp[j][k] + mp[k][i] == )
st.insert(cal(i, j, k));
} inline void del(int i, int j, int k) {
if (mp[i][j] + mp[j][k] + mp[k][i] == )
st.erase(cal(i, j, k));
} void solve(int i, int j) {
for (int k = ; k <= n; k++)
if (k != i && k != j)
del(i, j, k);
mp[i][j] ^= , mp[j][i] ^= ;
for (int k = ; k <= n; k++)
if (k != i && k != j)
add(i, j, k);
} void dfs(int dep) {
if (st.empty()) ans = std::min(ans, dep - );
if (dep >= ans) return;
int t = st.edge[], c = t % n + , b = t / n % n + , a = t / n / n + ;
solve(a, b); dfs(dep + ); solve(a, b);
solve(b, c); dfs(dep + ); solve(b, c);
solve(a, c); dfs(dep + ); solve(a, c);
} int main() {
int T;
scanf("%d", &T);
for (int kase = ; kase <= T; kase++) {
scanf("%d", &n);
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++)
scanf("%d", &mp[i][j]);
st.clear();
for (int i = ; i <= n; i++)
for (int j = i + ; j <= n; j++)
for (int k = j + ; k <= n; k++)
add(i, j, k);
ans = ;
dfs();
printf("Case #%d: %d\n", kase, ans == ? - : ans);
}
return ;
}

[K. Finding Hotels]

KD-tree查最近点对。用最小花费和估价函数剪枝。

#include <bits/stdc++.h>
#define ll long long
#define pii pair<ll, int>
#define fi first
#define se second namespace IO
{
char buf[ << ], buf2[ << ], a[], *p1 = buf, *p2 = buf, hh = ' ';
int p, p3 = -;
void read() {}
void print() {}
inline int getc() {
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, , << , stdin), p1 == p2) ? EOF : *p1++;
}
inline void flush() {
fwrite(buf2, , p3 + , stdout), p3 = -;
}
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth) {
T f = ; x = ;
char ch = getc();
while (!isdigit(ch)) { if (ch == '-') f = -; ch = getc(); }
while (isdigit(ch)) { x = x * + ch - ; ch = getc(); }
x *= f;
read(oth...);
}
template <typename T, typename... T2>
inline void print(T x, T2... oth) {
if (p3 > << ) flush();
if (x < ) buf2[++p3] = , x = -x;
do {
a[++p] = x % + ;
} while (x /= );
do {
buf2[++p3] = a[p];
} while (--p);
buf2[++p3] = hh;
print(oth...);
}
} // using namespace IO
#define read IO::read
#define print IO::print
#define flush IO::flush template<class T> inline void checkmax(T &a, T b) { if (a < b) a = b; }
template<class T> inline void checkmin(T &a, T b) { if (a > b) a = b; }
ll sqr(int x) { return 1LL * x * x; } const int N = 2e5 + ;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
int n, m, D, root;
std::pii ans; struct Node {
int lp, rp, id;
int d[], mx[], mn[];
inline bool operator < (const Node &rhs) const {
return d[D] < rhs.d[D];
}
void clear() {
lp = rp = id = ;
for (int i = ; i < ; i++)
d[i] = mx[i] = mn[i] = ;
}
} tree[N], qu, in[N]; struct Kd {
#define lp tree[p].lp
#define rp tree[p].rp
inline void pushup(int p, int s) {
for (int i = ; i < ; i++)
checkmax(tree[p].mx[i], tree[s].mx[i]),
checkmin(tree[p].mn[i], tree[s].mn[i]);
}
inline void pushup(int p) {
for (int i = ; i < ; i++)
tree[p].mx[i] = tree[p].mn[i] = tree[p].d[i];
if (lp) pushup(p, lp);
if (rp) pushup(p, rp);
}
int build(int l, int r, int d) {
D = d;
int mid = l + r >> , p = mid;
std::nth_element(tree + l, tree + mid, tree + r + );
if (l != mid) lp = build(l, mid - , (d + ) % );
else lp = ;
if (r != mid) rp = build(mid + , r, (d + ) % );
else rp = ;
pushup(p);
return p;
}
ll gu(int p) {
if (qu.d[] < tree[p].mn[]) return inf + ;
ll ret = ;
for (int i = ; i < ; i++) {
if (qu.d[i] > tree[p].mx[i]) ret += sqr(qu.d[i] - tree[p].mx[i]);
if (qu.d[i] < tree[p].mn[i]) ret += sqr(qu.d[i] - tree[p].mn[i]);
}
return ret;
}
ll dis(int p) {
if (qu.d[] < tree[p].d[]) return inf + ;
ll ret = ;
for (int i = ; i < ; i++)
ret += sqr(qu.d[i] - tree[p].d[i]);
return ret;
}
void query(int p) {
if (!p) return;
ll cur = dis(p);
if (cur < ans.fi || (cur == ans.fi && tree[p].id < ans.se))
ans.fi = cur, ans.se = tree[p].id;
ll dl = , dr = ;
if (lp) dl = gu(lp);
if (rp) dr = gu(rp);
if (dl < dr) {
if (dl <= ans.fi && lp) query(lp);
if (dr <= ans.fi && rp) query(rp);
} else {
if (dr <= ans.fi && rp) query(rp);
if (dl <= ans.fi && lp) query(lp);
}
}
} kd; int main() {
freopen("in.txt", "r", stdin);
int T;
read(T);
for ( ; T--; ) {
read(n, m);
for (int i = ; i <= n; i++) {
tree[i].clear();
tree[i].id = i;
for (int j = ; j < ; j++)
read(tree[i].d[j]);
in[i] = tree[i];
}
root = kd.build(, n, );
for (int i = ; i <= m; i++) {
ans.fi = inf, ans.se = ;
for (int j = ; j < ; j++)
read(qu.d[j]);
kd.query(root);
printf("%d %d %d\n", in[ans.se].d[], in[ans.se].d[], in[ans.se].d[]);
}
}
return ;
}

[L. Tower Attack]

用ST表+欧拉序维护LCA,$O(1)$ 得到LCA,再用ST表维护dfs序的区间直径,$O(1)$ 得到合并后的区间直径。(第二部分用了线段树狂T)

删去两条边后,最多产生 $5$ 个dfs序区间,考虑几种合并情况即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector> inline void checkmax(int &a, int b) { if (a < b) a = b; }
inline void checkmin(int &a, int b) { if (a > b) a = b; } namespace IO
{
char buf[ << ], buf2[ << ], a[], *p1 = buf, *p2 = buf, hh = '\n';
int p, p3 = -;
void read() {}
void print() {}
inline int getc() {
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, , << , stdin), p1 == p2) ? EOF : *p1++;
}
inline void flush() {
fwrite(buf2, , p3 + , stdout), p3 = -;
}
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth) {
T f = ; x = ;
char ch = getc();
while (!isdigit(ch)) { if (ch == '-') f = -; ch = getc(); }
while (isdigit(ch)) { x = x * + ch - ; ch = getc(); }
x *= f;
read(oth...);
}
template <typename T, typename... T2>
inline void print(T x, T2... oth) {
if (p3 > << ) flush();
if (x < ) buf2[++p3] = , x = -x;
do {
a[++p] = x % + ;
} while (x /= );
do {
buf2[++p3] = a[p];
} while (--p);
buf2[++p3] = hh;
print(oth...);
}
} // using namespace IO
#define read IO::read
#define print IO::print
#define flush IO::flush
#define pii pair<int, int>
#define fi first
#define se second
#define pb push_back const int N = 1e5 + ;
const int INF = 0x3f3f3f3f;
int n, q, dep[N], dis[N], dfn[N], in[N], out[N], tol, pos[N], euler[ * N];
int st[ * N][], lg[ * N]; struct E {
int v, ne, w;
} e[N << ];
int head[N], cnt; inline void add(int u, int v, int w) {
e[++cnt].v = v; e[cnt].ne = head[u]; e[cnt].w = w; head[u] = cnt;
} struct Edge {
int u, v, w;
} edge[N]; void dfs1(int u, int fa) {
dfn[in[u] = ++tol] = u;
for (int i = head[u]; i; i = e[i].ne) {
int v = e[i].v, w = e[i].w;;
if (v == fa) continue;
dis[v] = dis[u] + w;
dep[v] = dep[u] + ;
dfs1(v, u);
}
out[u] = tol;
} void dfs2(int u, int fa) {
euler[pos[u] = ++tol] = u;
for (int i = head[u]; i; i = e[i].ne) {
int v = e[i].v, w = e[i].w;;
if (v == fa) continue;
dfs2(v, u);
euler[++tol] = u;
}
} inline int min(int a, int b) {
return dep[euler[a]] < dep[euler[b]] ? a : b;
} void init() {
for (int i = ; i <= * n - ; i++)
st[i][] = i;
for (int j = ; ( << j) <= * n - ; j++)
for (int i = ; i + ( << j) - <= * n - ; i++)
st[i][j] = min(st[i][j - ], st[i + ( << (j - ))][j - ]);
} inline int Lca(int u, int v) {
u = pos[u], v = pos[v];
if (u > v) std::swap(u, v);
int logg = lg[v - u + ];
int lca = euler[min(st[u][logg], st[v - ( << logg) + ][logg])];
return lca;
} inline int getdis(int u, int v) {
return dis[u] + dis[v] - * dis[Lca(u, v)];
} /*struct Seg {
#define lp p << 1
#define rp p << 1 | 1
int tree[N << 2], p1[N << 2], p2[N << 2];
void pushup(int p) {
checkmax(tree[p], tree[lp]);
checkmax(tree[p], tree[rp]);
int lu = p1[lp], lv = p2[lp], ru = p1[rp], rv = p2[rp];
checkmax(tree[p], getdis(lu, ru));
checkmax(tree[p], getdis(lu, rv));
checkmax(tree[p], getdis(lv, ru));
checkmax(tree[p], getdis(lv, rv));
if (tree[p] == tree[lp])
p1[p] = p1[lp], p2[p] = p2[lp];
else if (tree[p] == tree[rp])
p1[p] = p1[rp], p2[p] = p2[rp];
else if (tree[p] == getdis(lu, ru))
p1[p] = lu, p2[p] = ru;
else if (tree[p] == getdis(lu, rv))
p1[p] = lu, p2[p] = rv;
else if (tree[p] == getdis(lv, ru))
p1[p] = lv, p2[p] = ru;
else
p1[p] = lv, p2[p] = rv;
}
void build(int p, int l, int r) {
tree[p] = 0;
if (l == r) {
p1[p] = p2[p] = dfn[l];
return;
}
int mid = l + r >> 1;
build(lp, l, mid);
build(rp, mid + 1, r);
pushup(p);
}
std::pii query(int p, int l, int r, int x, int y) {
if (x > y || x > r || y < l) return std::pii(INF, INF);
if (x <= l && y >= r) return std::pii(p1[p], p2[p]);
int mid = l + r >> 1;
if (x > mid) return query(rp, mid + 1, r, x, y);
if (y <= mid) return query(lp, l, mid, x, y);
auto pp = query(lp, l, mid, x, y), qq = query(rp, mid + 1, r, x, y);
int len = 0;
checkmax(len, getdis(pp.fi, pp.se));
checkmax(len, getdis(qq.fi, qq.se));
checkmax(len, getdis(pp.fi, qq.fi));
checkmax(len, getdis(pp.fi, qq.se));
checkmax(len, getdis(pp.se, qq.fi));
checkmax(len, getdis(pp.se, qq.se));
if (len == getdis(pp.fi, pp.se)) return pp;
if (len == getdis(qq.fi, qq.se)) return qq;
if (len == getdis(pp.fi, qq.fi)) return std::pii(pp.fi, qq.fi);
if (len == getdis(pp.fi, qq.se)) return std::pii(pp.fi, qq.se);
if (len == getdis(pp.se, qq.fi)) return std::pii(pp.se, qq.fi);
return std::pii(pp.se, qq.se);
}
} seg;*/ std::pii merge(const std::pii &x, const std::pii &y) {
if (x.fi == INF || x.se == INF) return y;
if (y.fi == INF || y.se == INF) return x;
int ans = ;
checkmax(ans, getdis(x.fi, x.se));
checkmax(ans, getdis(y.fi, y.se));
checkmax(ans, getdis(x.fi, y.fi));
checkmax(ans, getdis(x.fi, y.se));
checkmax(ans, getdis(x.se, y.fi));
checkmax(ans, getdis(x.se, y.se));
if (ans == getdis(x.fi, x.se)) return x;
if (ans == getdis(y.fi, y.se)) return y;
if (ans == getdis(x.fi, y.fi)) return std::pii(x.fi, y.fi);
if (ans == getdis(x.fi, y.se)) return std::pii(x.fi, y.se);
if (ans == getdis(x.se, y.fi)) return std::pii(x.se, y.fi);
return std::pii(x.se, y.se);
} struct ST {
std::pii St[N][];
void build() {
for (int i = ; i <= n; i++)
St[i][].fi = St[i][].se = dfn[i];
for (int j = ; ( << j) <= n; j++)
for (int i = ; i + ( << j) - <= n; i++)
St[i][j] = merge(St[i][j - ], St[i + ( << (j - ))][j - ]);
}
std::pii query(int l, int r) {
if (l > r) return std::pii(INF, INF);
int logg = lg[r - l + ];
return merge(St[l][logg], St[r - ( << logg) + ][logg]);
}
} St; int main() {
//freopen("in.txt", "r", stdin);
int T;
read(T);
for (int i = , j = ; i < * N; i++)
lg[i] = (( << (j + )) == i) ? ++j : j;
for ( ; T-- ; ) {
read(n, q);
cnt = ;
for (int i = ; i <= n; i++) {
dep[i] = dis[i] = ;
in[i] = out[i] = pos[i] = ;
head[i] = ;
}
for (int i = , u, v, w; i < n; i++) {
read(edge[i].u, edge[i].v, edge[i].w);
u = edge[i].u, v = edge[i].v, w = edge[i].w;
add(u, v, w); add(v, u, w);
}
tol = ;
dfs1(, );
tol = ;
dfs2(, );
init();
for (int i = ; i < n; i++)
if (dep[edge[i].u] > dep[edge[i].v])
std::swap(edge[i].u, edge[i].v);
//seg.build(1, 1, n);
St.build();
for (int i = , u, v, lca; i <= q; i++) {
read(u, v);
u = edge[u].v, v = edge[v].v, lca = Lca(u, v);
int ans = ;
if (lca != u && lca != v) {
if (in[u] > in[v]) std::swap(u, v);
auto p1 = St.query(, in[u] - ), p2 = St.query(out[u] + , in[v] - ), p3 = St.query(out[v] + , n);
p1 = merge(p1, merge(p2, p3));
checkmax(ans, getdis(p1.fi, p1.se));
p1 = St.query(in[u], out[u]);
checkmax(ans, getdis(p1.fi, p1.se));
p1 = St.query(in[v], out[v]);
checkmax(ans, getdis(p1.fi, p1.se));
} else {
if (u != lca) std::swap(u, v);
auto p1 = St.query(, in[u] - ), p2 = St.query(out[u] + , n);
p1 = merge(p1, p2);
checkmax(ans, getdis(p1.fi, p1.se));
p1 = St.query(in[u], in[v] - ), p2 = St.query(out[v] + , out[u]);
p1 = merge(p1, p2);
checkmax(ans, getdis(p1.fi, p1.se));
p1 = St.query(in[v], out[v]);
checkmax(ans, getdis(p1.fi, p1.se));
}
print(ans);
}
}
flush();
return ;
}

[M. Generator and Monitor]

问题转化为 操作 $1$ 加入一个点 $(x, y)$,权值为 $c$。操作 $2$ 给出一个 $pos$,将所有点 $(x, y)$ 满足 $x \leq pos \wedge y \geq pos$ 的权值,并把权值为 $0$ 的点的编号输出并删除。

可以想到用KD-tree维护这么一些点,维护最小权值,以及懒标记维护修改。

删除的地方太过暴力...维护最小权值的节点编号,将这个点的到根的链从上到下把标记pushdown。将其权值修改为INF再从下到上pushup一遍。KDtree期望树高 $O(logn)$,所以可以这么做。

#include <bits/stdc++.h>

namespace IO {
void read() {}
template<class T, class... T2>
inline void read(T &x, T2 &... oth) {
x = ; T f = ; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') f = -; ch = getchar(); }
while (isdigit(ch)) x = x * + ch - , ch = getchar();
x *= f;
read(oth...);
}
} using namespace IO; const int N = 4e5 + ;
const int INF = 0x3f3f3f3f; template<class T>
inline bool chkmin(T &a, const T &b) {
return a > b ? a = b, : ;
} template<class T>
inline bool chkmax(T &a, const T &b) {
return a < b ? a = b, : ;
} int n, m, D, id[N], tol; struct Node {
int lp, rp, id, pos, fa;
int d[], mx[], mn[];
int v, minv, add;
inline bool operator < (const Node &rhs) const {
return d[D] < rhs.d[D];
}
inline void init() {
minv = v = pos = INF, add = ;
for (int i = ; i < ; i++)
mx[i] = mn[i] = d[i];
}
}; struct IN {
int x, y, c;
} p[N]; namespace KD {
#define lp tree[p].lp
#define rp tree[p].rp
Node tree[N];
int root;
inline void pushup(int p, int s) {
if (chkmin(tree[p].minv, tree[s].minv))
tree[p].pos = tree[s].pos;
for (int i = ; i < ; i++)
chkmin(tree[p].mn[i], tree[s].mn[i]), chkmax(tree[p].mx[i], tree[s].mx[i]);
}
inline void pushup(int p) {
tree[p].minv = tree[p].v;
tree[p].pos = tree[p].id;
if (lp) pushup(p, lp);
if (rp) pushup(p, rp);
}
inline void tag(int p, int val) {
tree[p].minv += val;
tree[p].v += val;
tree[p].add += val;
}
inline void pushdown(int p) {
if (!tree[p].add) return;
if (lp) tag(lp, tree[p].add);
if (rp) tag(rp, tree[p].add);
tree[p].add = ;
}
void down(int p) {
if (tree[p].fa) down(tree[p].fa);
pushdown(p);
}
int build(int l, int r, int d, int fa) {
int mid = l + r >> ;
D = d;
std::nth_element(tree + l, tree + mid, tree + r + );
int p = mid;
id[tree[p].id] = p;
tree[p].fa = fa;
tree[p].init();
if (l != mid) lp = build(l, mid - , d ^ , p);
else lp = ;
if (r != mid) rp = build(mid + , r, d ^ , p);
else rp = ;
pushup(p);
return p;
}
void add(int p, int v) {
down(p);
tree[p].v = v;
while (p) {
pushup(p);
p = tree[p].fa;
}
}
int check(int minx, int maxx, int miny, int maxy, int x) {
if (maxx <= x && miny >= x) return ;
if (minx <= x && maxy >= x) return ;
return ;
}
void update(int p, int x, int v) {
int d = check(tree[p].mn[], tree[p].mx[], tree[p].mn[], tree[p].mx[], x);
if (!d) {
tag(p, v);
return;
}
if (d == ) return;
if (tree[p].d[] <= x && tree[p].d[] >= x) {
tree[p].v += v;
tree[p].minv += v;
}
pushdown(p);
if (lp) update(lp, x, v);
if (rp) update(rp, x, v);
pushup(p);
}
} using namespace KD; void init() {
tol = ;
read(n, m);
for (int i = ; i <= n; i++) {
static char s[];
scanf("%s", s);
if (s[] == 'C') {
read(p[i].x, p[i].y, p[i].c);
tol++;
tree[tol].d[] = p[i].x;
tree[tol].d[] = p[i].y;
tree[tol].id = i;
} else {
p[i].c = ;
read(p[i].x);
}
}
} void solve() {
root = build(, tol, , );
tree[root].fa = ;
int res = ;
for (int i = ; i <= n; i++) {
if (p[i].c) add(id[i], p[i].c);
else update(root, p[i].x ^ res, -);
int val = ;
std::vector<int> temp;
while (!tree[root].minv) {
val ^= tree[root].pos;
temp.push_back(tree[root].pos);
add(id[tree[root].pos], INF);
}
res ^= val;
if (!temp.empty()) {
printf("%d", i);
sort(temp.begin(), temp.end());
for (int x: temp)
printf(" %d", x);
puts("");
}
}
} int main() {
freopen("in.txt", "r", stdin);
int T;
read(T);
for (int i = ; i <= T; i++) {
printf("Case #%d:\n", i);
init();
solve();
}
}

2016 ACM/ICPC亚洲区青岛站的更多相关文章

  1. 2016 ACM/ICPC亚洲区青岛站现场赛(部分题解)

    摘要 本文主要列举并求解了2016 ACM/ICPC亚洲区青岛站现场赛的部分真题,着重介绍了各个题目的解题思路,结合详细的AC代码,意在熟悉青岛赛区的出题策略,以备战2018青岛站现场赛. HDU 5 ...

  2. 2016 ACM/ICPC亚洲区大连站-重现赛 解题报告

    任意门:http://acm.hdu.edu.cn/showproblem.php?pid=5979 按AC顺序: I - Convex Time limit    1000 ms Memory li ...

  3. 2016 ACM/ICPC亚洲区大连站 F - Detachment 【维护前缀积、前缀和、二分搜索优化】

    F - Detachment In a highly developed alien society, the habitats are almost infinite dimensional spa ...

  4. 2016 ACM/ICPC亚洲区沈阳站

    A B C D E F G H I J K L M O O O $\varnothing$ $\varnothing$   $\varnothing$ $\varnothing$ $\varnothi ...

  5. 2012 ACM/ICPC 亚洲区 金华站

    题目链接  2012金华区域赛 Problem A 按a/b从小到大的顺序排队进行体检即可 #include<iostream> #include<cstdio> #inclu ...

  6. 2013 ACM/ICPC 亚洲区 杭州站

    题目链接  2013杭州区域赛 Problem A Problem B 这题我用的是SPFA+ mask dp 首先跑5次SPFA: 1次是求出每个起点和其他所有点的最短距离 4次是求出每个输入的点和 ...

  7. Hdu-5992 2016ACM/ICPC亚洲区青岛站 K.Finding Hotels KDtree

    题面 题意:二维平面上有很多点,每个点有个权值,现在给你一个点(很多组),权值v,让你找到权值小于等于v的点中离这个点最近的,相同的输出id小的 题解:很裸的KDtree,但是查询的时候有2个小限制, ...

  8. Hdu-5983 2016ACM/ICPC亚洲区青岛站 B.Pocket Cube 模拟

    题面 题意:给你一个2*2的魔方,给你每个面每个小块的颜色,一共24个,然后问你能否在一步之内还原. 题解:手动在纸上画,推出每种变化对应的置换,显然,一共有6种,而且可以当成3种,(具体哪3种,就是 ...

  9. 2016 ACM/ICPC Asia Regional Qingdao Online(2016ACM青岛网络赛部分题解)

    2016 ACM/ICPC Asia Regional Qingdao Online(部分题解) 5878---I Count Two Three http://acm.hdu.edu.cn/show ...

随机推荐

  1. 推荐一款万年历App 诸葛万年历

    推荐一款万年历App 诸葛万年历 1 介绍 应用简介: 提供标准和专业的时间信息查询,记录和承载生活中的美好记忆,帮助用户高效快捷的管理个人时间.精美的日期展示和完善的重要事件提醒功能,可以方便安排日 ...

  2. innodb部分内部操作

    tab_node_t* tab_create_graph_create( /*====================*/ dict_table_t* table, /*!< in: table ...

  3. scala基础题--100以内的数求和,求出当和第一次大于20的当前数【for】

    import util.control.Breaks._ object work01 { def main(args: Array[String]): Unit = { //方式一 var sum:I ...

  4. HDU 2007-11 Programming Contest

    Can you find it? Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/10000 K (Java/Others ...

  5. Redis(七)持久化(Persistence)

    前言 前文中介绍到Redis时内存的K-V数据结构存储服务器.Redis的高性能原因之一在于其读写数据都是在内存中进行.它的架构实现方式决定了Redis的数据存储具有不可靠性,易丢失,因为RAM内存在 ...

  6. CSS实现水平垂直居中的数种方法整合

    CSS实现水平垂直居中可以说是前端老生常谈的问题了,一般面试官问的时候面试者都会回答出来,但是继续追问还有没有其他方法的时候有可能就说不出来了. 本着学习知识的目的,特在此纪录CSS实现水平垂直居中的 ...

  7. android 入门开发

    本示例讲解的是基本点有 1.使用SQLite数据库 2.对数据的新增,查询. 3.利用ViewActivity进行数据的呈现 代码是参考了网上各种代码,刚开始写,肯定有一些地方是有问题,我对JAVA代 ...

  8. 在IIS下发布.Net Core MVC项目

    1. 默认你已经安装了IIS,并且创建了一个.Net Core 项目 2. 发布.NET Core项目 在vs中右键点击MVC项目,点击"发布"按钮,选择"文件系统&qu ...

  9. 一文搞定十大经典排序算法(Java实现)

    本文总结十大经典排序算法及变形,并提供Java实现. 参考文章: 十大经典排序算法总结(Java语言实现) 快速排序算法—左右指针法,挖坑法,前后指针法,递归和非递归 快速排序及优化(三路划分等) 一 ...

  10. 开发--Deepin系统安装

    开发|Deepin系统安装 在18小时前,我刚刚萌生了一个将我的笔记本换成linux系统.在18小时后的现在,在我各种试错之后,笔记本已经开始跑起linux了.在科技的时代,只要是想法,都可以试一试. ...