2019 - 2020 ICPC, 아시아 자카르타 지역 대회 부분 해제
82658 단어 경기데이터 구조 - 선분 트 리동적 계획
제목: 서열 A A A A 를 드 리 겠 습 니 다. 사전 서열 의 가장 작은 서열 B B B B 를 구성 하고 구조 요소 의 수치 범 위 를 [l, r] [l, r] [l, r] [l, r] 로 만족 시 켜 야 합 니 다. 또한 인접 요소 의 차 이 는 K K K 를 초과 하지 않 으 며 인접 요소 의 크기 관계 와 서열 A A A 가 대응 하 는 원소 유지 와 일치 합 니 다.
해법: 이 문 제 는 예전 에 풀 었 던 것 같 지만 이번 에는 풀 지 못 했 습 니 다. 우 리 는 L i, R i L 을 기억 합 니 다.{i},R_{i} Li, Ri 는 각각 B i B{i} Bi 의 합 법 적 인 수치 범위, 우 리 는 B B B 서열 을 거꾸로 밀어 L n = l, R n = r L 을 초기 화 합 니 다.{n}=l,R_{n} = r Ln = l, Rn = r, 만약 A i > A i + 1 A{i}>A_{i + 1} Ai > Ai + 1 그러면 R i = m i n (r, R i + 1 + k), L i = L i + 1 + 1 R{i}=min(r,R_{i+1}+k),L_{i}=L_{i + 1} + 1 Ri = min (r, Ri + 1 + k), Li = Li + 1 + 1, 만약 A i < A i + 1 A{i} Ai < Ai + 1, 그러면 R i = R i + 1 − 1, L i = m a x (l, L i + 1 − k) R{i}=R_{i+1}-1,L_{i} = max (l, L {i + 1} - k) Ri = Ri + 1 − 1, Li = max (l, Li + 1 − k), L i, R i L 구하 기{i},R_{i} Li, Ri 후 순 으로 구 조 를 밀어 내 면 됩 니 다.
#include
using namespace std;
const int maxn = 1e5 + 10;
int L[maxn], R[maxn], a[maxn], b[maxn];
int main()
{
int n, l, r, k;
scanf("%d%d%d%d", &n, &l, &r, &k);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
L[n] = l, R[n] = r;
for (int i = n - 1; i; i--)
{
if (a[i] > a[i + 1])
{
R[i] = min(r, R[i + 1] + k);
L[i] = L[i + 1] + 1;
}
else if (a[i] < a[i + 1])
{
L[i] = max(l, L[i + 1] - k);
R[i] = R[i + 1] - 1;
}
else
L[i] = L[i + 1], R[i] = R[i + 1];
if (L[i] > R[i])
return puts("-1"), 0;
}
int x = L[1];
printf("%d", L[1]);
for (int i = 2; i <= n; i++)
{
if (a[i] > a[i - 1])
x = max(x + 1, L[i]);
else if (a[i] < a[i - 1])
x = max(L[i], x - k);
printf(" %d", x);
}
}
F. Regular Forestation
제목: 나무 한 그루 에 도수 의 최대 점 을 구하 고 도수 가 1 보다 많 으 면 이 점 이 뿌리 인 모든 하위 나무의 구조 가 같 고 출력 도수 가 같다.
해법: 누 드 트 리 hash, 하지만 모든 점 을 매 거 해 야 합 니 다. 그러면 뿌리 dp 를 바 꾸 어 모든 점 을 뿌리 로 하 는 나무 hash 를 구하 면 됩 니 다. 복잡 도 nlogn
#include
#define ll long long
using namespace std;
const int maxn = 4005, mod1 = 998244353, mod2 = 1e9 + 7;
vector<int> G[maxn];
int p1[maxn], p2[maxn];
struct Hash
{
int h1, h2, len;
} d[maxn];
vector<Hash> S[maxn];
int ans = -1;
bool cmp(int a, int b)
{
return d[a].h1 < d[b].h1 || (d[a].h1 == d[b].h1 && d[a].h2 < d[b].h2);
}
Hash merge(Hash a, Hash b)
{
Hash jie = Hash{
0, 0, a.len + b.len};
jie.h1 = (1ll * a.h1 * p1[b.len] + b.h1) % mod1;
jie.h2 = (1ll * a.h2 * p2[b.len] + b.h2) % mod2;
return jie;
}
void dfs(int u, int fa)
{
d[u] = Hash{
1, 1, 1};
for (auto v : G[u])
if (v != fa)
dfs(v, u);
sort(G[u].begin(), G[u].end(), cmp);
for (auto v : G[u])
if (v != fa)
d[u] = merge(d[u], d[v]);
}
void dfs2(int u, int fa)
{
d[u] = Hash{
1, 1, 1};
sort(G[u].begin(), G[u].end(), cmp);
Hash cat{
0, 0, 0};
int jie = 1;
S[u].push_back(Hash{
1, 1, 1});
for (auto v : G[u])
{
d[u] = merge(d[u], d[v]);
if (cat.len == 0)
cat = d[v];
else if (cat.h1 != d[v].h1 || cat.h2 != d[v].h2)
jie = 0;
S[u].push_back(d[u]);
}
if (jie && G[u].size() > 1)
ans = max(ans, (int)G[u].size());
Hash nvshen{
0, 0, 0};
for (int i = G[u].size() - 1; ~i; i--)
{
d[u] = merge(S[u][i], nvshen);
nvshen = merge(d[G[u][i]], nvshen);
if (G[u][i] != fa)
dfs2(G[u][i], u);
}
}
int main()
{
p1[0] = p2[0] = 1;
for (int i = 1; i < maxn; i++)
{
p1[i] = 1ll * p1[i - 1] * 199967 % mod1;
p2[i] = 1ll * p2[i - 1] * 199999 % mod2;
}
int n, u, v;
scanf("%d", &n);
for (int i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
dfs2(1, 0);
printf("%d
", ans);
}
G. Performance Review
제목: n n n 의 개인 능력 치 를 제시 합 니 다. 당신 은 첫 번 째 사람 입 니 다. 그리고 m m 의 변동 을 제시 합 니 다. 매번 변동 회사 의 해고 능력 치가 가장 낮은 k k k 개인 은 모든 사람의 능력 치가 서로 다 르 도록 보장 한 다음 에 k k k 개인 에 가입 하고 그들의 능력 치 를 제시 합 니 다.그리고 m m 차 변동 후 잘 리 냐 고 물 었 습 니 다. 매번 작업 의 수정 은 영구적 으로 수정 되 었 습 니 다 (다음 작업 에 영향 을 줍 니 다).
해법: 우리 p i p{i} pi 는 전 i i 차 변동 중 능력 치가 나 보다 낮은 사람의 총 수량, s u m i sum{i} sumi 는 전 i i 차 작업 에서 자 른 사람의 수 를 합 쳐 라인 트 리 로 p i - s u m i p 를 유지 합 니 다.{i}-sum_{i} pi − sumi 의 최소 값 이면 됩 니 다. 최소 값 이 0 보다 적 으 면 잘 릴 것 입 니 다.
#include
using namespace std;
const int maxn = 1e5 + 10;
int mn[maxn * 4], tag[maxn * 4], a[maxn];
vector<int> b[maxn];
#define ls o * 2
#define rs o * 2 + 1
#define mid (l + r) / 2
void pushdown(int o)
{
if (tag[o])
{
tag[ls] += tag[o];
tag[rs] += tag[o];
mn[ls] += tag[o];
mn[rs] += tag[o];
tag[o] = 0;
}
}
void up(int o, int l, int r, int ql, int qr, int v)
{
if (l >= ql && r <= qr)
{
mn[o] += v;
tag[o] += v;
return;
}
pushdown(o);
if (ql <= mid)
up(ls, l, mid, ql, qr, v);
if (qr > mid)
up(rs, mid + 1, r, ql, qr, v);
mn[o] = min(mn[ls], mn[rs]);
}
int main()
{
int n, m, q, res = 0, sum = 0, k, x, v;
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
if (i > 1 && a[i] < a[1])
res++;
}
for (int i = 1; i <= m; i++)
{
scanf("%d", &k);
sum += k;
up(1, 1, m, i, i, res - sum);
for (int j = 1; j <= k; j++)
{
scanf("%d", &x);
if (x < a[1])
res++;
b[i].push_back(x);
}
}
while (q--)
{
scanf("%d%d%d", &k, &x, &v);
if (b[k][x - 1] > a[1])
{
if (v < a[1] && k < m)
up(1, 1, m, k + 1, m, 1);
}
else
{
if (v > a[1] && k < m)
up(1, 1, m, k + 1, m, -1);
}
b[k][x - 1] = v;
if (mn[1] < 0)
puts("0");
else
puts("1");
}
}
J. Tiling Terrace 보충, 인터넷 부분 문제 풀이 의 복잡 도 의심... K. Addition Robot
제목: 문제 면 을 분명하게 말 하 다.
해법: 누 드 라인 트 리 유지 행렬 곱셈
#include
#define ll long long
#define ls o * 2
#define rs o * 2 + 1
#define mid (l + r) / 2
using namespace std;
const int maxn = 1e5 + 10, mod = 1e9 + 7;
void add(int &x, int y)
{
x += y;
if (x >= mod)
x -= mod;
if (x < 0)
x += mod;
}
struct seg
{
int A[2][2], B[2][2], tag;
seg operator+(const seg &t) const
{
seg jie;
jie.tag = 0;
memset(jie.A, 0, sizeof(jie.A));
memset(jie.B, 0, sizeof(jie.B));
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
{
add(jie.A[i][j], 1ll * A[i][k] * t.A[k][j] % mod);
add(jie.B[i][j], 1ll * B[i][k] * t.B[k][j] % mod);
}
return jie;
}
} cat[maxn * 4];
char s[maxn];
void build(int o, int l, int r)
{
if (l == r)
{
cat[o].A[0][0] = 1, cat[o].A[0][1] = 0, cat[o].A[1][0] = 1, cat[o].A[1][1] = 1;
cat[o].B[0][0] = 1, cat[o].B[0][1] = 1, cat[o].B[1][0] = 0, cat[o].B[1][1] = 1;
if (s[l] == 'B')
swap(cat[o].A, cat[o].B);
return;
}
build(ls, l, mid);
build(rs, mid + 1, r);
cat[o] = cat[ls] + cat[rs];
}
void pushdown(int o)
{
if (cat[o].tag)
{
swap(cat[ls].A, cat[ls].B);
cat[ls].tag ^= 1;
swap(cat[rs].A, cat[rs].B);
cat[rs].tag ^= 1;
cat[o].tag = 0;
}
}
void up(int o, int l, int r, int ql, int qr)
{
if (l >= ql && r <= qr)
{
swap(cat[o].A, cat[o].B);
cat[o].tag ^= 1;
return;
}
pushdown(o);
if (ql <= mid)
up(ls, l, mid, ql, qr);
if (qr > mid)
up(rs, mid + 1, r, ql, qr);
cat[o] = cat[ls] + cat[rs];
}
seg qu(int o, int l, int r, int ql, int qr)
{
if (l >= ql && r <= qr)
return cat[o];
pushdown(o);
if (qr <= mid)
return qu(ls, l, mid, ql, qr);
else if (ql > mid)
return qu(rs, mid + 1, r, ql, qr);
else
return qu(ls, l, mid, ql, qr) + qu(rs, mid + 1, r, ql, qr);
}
int main()
{
int n, q, opt, l, r, a, b;
scanf("%d%d%s", &n, &q, s + 1);
build(1, 1, n);
while (q--)
{
scanf("%d%d%d", &opt, &l, &r);
if (opt == 1)
up(1, 1, n, l, r);
else
{
scanf("%d%d", &a, &b);
seg jie = qu(1, 1, n, l, r);
ll ans1 = 1ll * a * jie.A[0][0] + 1ll * b * jie.A[1][0];
ll ans2 = 1ll * a * jie.A[0][1] + 1ll * b * jie.A[1][1];
printf("%lld %lld
", ans1 % mod, ans2 % mod);
}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
선분 트 리 - 구간 수정 + 조회 구간 최대 값제목. 설명 설명 은 하나의 수열 을 지정 하고 초기 값 은 모두 0 입 니 다. 현재 이 서열 에 대해 두 가지 조작 이 있 습 니 다. 조작 1: 첫 번 째 k1 개 를 두 번 째 k2 개 수 에 1 을 추가 합...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.