Petrozavodsk Winter 2018 - A. Mines - 세그먼트 트리 최적화 설계도, 강연통 분량 축소점,DP
문제풀이: 한 그루의 나무 한 그루를 짓고 각 아버지의 노드가 좌우 아들에게 각각 한 줄기 방향이 있다.그리고 천둥 하나하나를 매거하여, pi p 에서i pi가 있는 잎사귀 노드는 [p i -3 r i, p i + r i] [p i-r i, p i + r i] [pi -3 ri, pi +ri]에 대응하는 노드를 연결하고 tarjan은 scc를 한 번 구한다.잎 노드를 포함하는 scc에서 도착할 수 있는 모든 scc를 삭제하고 나머지 잎을 포함하는 scc의 최소값의 합이 답입니다.수정은 scc마다 멀티셋을 유지할 수 있습니다.시간 복잡도 O(n log n)\mathcal{O} (n\log{n}) O(nlogn).
코드:
#include
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const int maxm = maxn << 2;
vector g[maxm], h[maxm];
int dfn[maxm], low[maxm], belong[maxm], scc, cnt;
bool vis[maxm];
stack s;
void tarjan(int u) {
low[u] = dfn[u] = ++cnt;
s.push(u);
vis[u] = 1;
for (int v: g[u]) {
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (vis[v]) low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u]) {
++scc;
int v;
do {
v = s.top();
s.pop();
vis[v] = 0;
belong[v] = scc;
} while (u != v);
}
}
int id[maxn];
struct SegmentTree {
#define ls (rt<<1)
#define rs (rt<<1|1)
void build(int l, int r, int rt) {
if (l == r) {
id[l] = rt;
return;
}
int m = (l + r) / 2;
g[rt].push_back(ls);
g[rt].push_back(rs);
build(l, m, ls);
build(m+1, r, rs);
}
void query(int l, int r, int p, int L, int R, int rt) {
if (l <= L && R <= r) {
g[p].push_back(rt);
return;
}
int m = (L + R) / 2;
if (l <= m) query(l, r, p, L, m, ls);
if (r > m) query(l, r, p, m+1, R, rs);
}
} T;
struct node {
int p, r, c;
friend bool operator< (const node& x, const node& y) {
return x.p < y.p;
}
} a[maxn];
int rk[maxn], in[maxm];
vector> dx;
multiset ms[maxm];
bool ins[maxm];
int main() {
int n, q;
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &a[i].p, &a[i].r, &a[i].c);
dx.push_back({a[i].p, i});
}
sort(dx.begin(), dx.end());
T.build(1, n, 1);
for (int i = 1; i <= n; i++) {
rk[i] = lower_bound(dx.begin(), dx.end(), make_pair(a[i].p, i)) - dx.begin() + 1;
int l = lower_bound(dx.begin(), dx.end(), make_pair(a[i].p - a[i].r, 0)) - dx.begin() + 1;
int r = lower_bound(dx.begin(), dx.end(), make_pair(a[i].p + a[i].r + 1, 0)) - dx.begin();
T.query(l, r, id[rk[i]], 1, n, 1);
}
int m = 4 * n;
for (int i = 1; i <= m; i++) {
if (!dfn[i]) tarjan(i);
}
for (int i = 1; i <= scc; i++) vis[i] = 0;
for (int i = 1; i <= n; i++) {
vis[belong[id[rk[i]]]] = 1;
ms[belong[id[rk[i]]]].insert(a[i].c);
}
queue Q;
for (int u = 1; u <= m; u++) {
for (int v: g[u]) {
if (belong[u] != belong[v]) {
h[belong[u]].push_back(belong[v]);
if (vis[belong[u]]) {
++in[belong[v]];
if (!vis[belong[v]] && !ins[belong[v]]) {
Q.push(belong[v]);
ins[v] = 1;
}
}
}
}
}
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (int v: h[u]) {
in[v] += in[u];
if (!ins[v]) {
Q.push(v);
ins[v] = 1;
}
}
ins[u] = 0;
}
ll sum = 0;
for (int i = 1; i <= scc; i++) {
if (vis[i] && in[i] == 0) sum += *ms[i].begin();
}
while (q--) {
int x, y;
scanf("%d%d", &x, &y);
if (!in[belong[id[rk[x]]]]) {
sum -= *ms[belong[id[rk[x]]]].begin();
auto it = ms[belong[id[rk[x]]]].find(a[x].c);
ms[belong[id[rk[x]]]].erase(it);
ms[belong[id[rk[x]]]].insert(y);
sum += *ms[belong[id[rk[x]]]].begin();
a[x].c = y;
}
printf("%lld
", sum);
}
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
전략 게임(문제 해결 트리 DP)처음 트리 DP를 씁니다. 트리 DP에서 DP의 "단계"는 일반적으로 깊이에서 얕은(하위 트리가 작은 것부터 큰 것까지) 순서로 사용됩니다. 대부분의 경우 우리는 귀속 방식을 이용하여 트리 DP를 실현한다. 각 노드...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.