简述
突然记起来 CSP 前特别喜欢的 POI 题还有一堆没写,所以就有了这个坑。
「POI2015」TRZ
写起来还挺麻烦。
我们考虑先把条件写出来:
\[ \begin{cases} s_r^1 – s_{l – 1}^1 \neq s_r^2 – s_{l – 1}^2 \neq s_r^2 – s_{l – 1}^2 \neq s_r^1 – s_{l – 1}^1 \end{cases} \]
进行移项之后发现可以做成自身的特征:
\[ \begin{cases} s_r^1 – s_r^2 \neq s_{l – 1}^1 – s_{l – 1}^2 \\ s_r^1 – s_r^3 \neq s_{l – 1}^1 – s_{l – 1}^3 \\ s_r^2 – s_r^3 \neq s_{l – 1}^2 – s_{l – 1}^3 \end{cases} \]
我们需要找到最长的区间使得这个条件成立,那么其实这就是一个偏序问题。每一个三维的点每一维直接做成其特征即可。而这个偏序需要知道除自己以外的所有信息,所以不能像正常的偏序来搞。所以,我们来进行拼凑。考虑按 \(x\) 排序,然后把 \(y\) 插入权值线段树,最后每个节点维护两个不同的 \(z\) 的极点位置即可。有点难写。
const int MAX_N = 1e6 + 200, INF = 0x3f3f3f3f;
int lson, rson, max_val[2] = {-1, -1}, min_val[2] = {INF, INF};
bool operator<(const package &rhs) const { return x < rhs.x; }
} pre[MAX_N], ai[MAX_N], bi[MAX_N];
int update(int qx, int l, int r, int p, package val)
if (nodes[p].min_val[0] > val.id)
if (nodes[p].min_val[0] != INF && bi[nodes[p].min_val[0]].id != val.z)
nodes[p].min_val[1] = nodes[p].min_val[0];
nodes[p].min_val[0] = val.id;
else if (nodes[p].min_val[1] > val.id && bi[nodes[p].min_val[0]].z != val.z)
nodes[p].min_val[1] = val.id;
if (nodes[p].max_val[0] < val.id)
if (nodes[p].max_val[0] != -1 && bi[nodes[p].max_val[0]].z != val.z)
nodes[p].max_val[1] = nodes[p].max_val[0];
nodes[p].max_val[0] = val.id;
else if (nodes[p].max_val[1] < val.id && bi[nodes[p].max_val[0]].z != val.z)
nodes[p].max_val[1] = val.id;
nodes[p].lson = update(qx, l, mid, nodes[p].lson, val);
nodes[p].rson = update(qx, mid + 1, r, nodes[p].rson, val);
int query(int ql, int qr, int l, int r, int p, package val)
if (nodes[p].min_val[0] == INF)
min_val = (val.z == bi[nodes[p].min_val[0]].z) ? nodes[p].min_val[1] : nodes[p].min_val[0];
max_val = (val.z == bi[nodes[p].max_val[0]].z) ? nodes[p].max_val[1] : nodes[p].max_val[0];
if (min_val == INF || max_val == -1)
return max(abs(val.id - min_val), abs(val.id - max_val));
int mid = (l + r) >> 1, ret = 0;
ret = max(ret, query(ql, qr, l, mid, nodes[p].lson, val));
ret = max(ret, query(ql, qr, mid + 1, r, nodes[p].rson, val));
for (int i = 0, ptr = 0; i < n; i++)
ans = max(ans, i - ptr + 1);
for (int i = 1; i <= n; i++)
for (int i = 1; i <= n; i++)
ai[i].x = pre[i].x - pre[i].y;
ai[i].y = pre[i].x - pre[i].z;
ai[i].z = pre[i].y - pre[i].z;
lower = min(lower, min(ai[i].x, min(ai[i].y, ai[i].z)));
for (int i = 1; i <= n; i++)
ai[i].x -= lower - 1, ai[i].y -= lower - 1, ai[i].z -= lower - 1;
for (int i = 1; i <= n; i++)
bi[0] = bi[n], sort(ai + 1, ai + 1 + n);
int domain = n - lower + 1;
for (int i = 1, ptr = 1; i <= n; i++)
if (ai[i].x != ai[ptr].x)
if (ai[i].x != ai[i + 1].x)
for (int j = ptr; j <= i; j++)
ans = max(ans, max(query(1, ai[j].y - 1, 1, domain, 1, ai[j]), query(ai[j].y + 1, domain, 1, domain, 1, ai[j])));
for (int j = ptr; j <= i; j++)
update(ai[j].y, 1, domain, 1, ai[j]);
// P3590.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200, INF = 0x3f3f3f3f;
int n, ans, ptot = 1;
char str[MAX_N];
struct node
{
int lson, rson, max_val[2] = {-1, -1}, min_val[2] = {INF, INF};
} nodes[MAX_N * 3];
struct package
{
int id, x, y, z;
bool operator<(const package &rhs) const { return x < rhs.x; }
} pre[MAX_N], ai[MAX_N], bi[MAX_N];
int update(int qx, int l, int r, int p, package val)
{
if (p == 0)
p = ++ptot;
if (nodes[p].min_val[0] > val.id)
{
if (nodes[p].min_val[0] != INF && bi[nodes[p].min_val[0]].id != val.z)
nodes[p].min_val[1] = nodes[p].min_val[0];
nodes[p].min_val[0] = val.id;
}
else if (nodes[p].min_val[1] > val.id && bi[nodes[p].min_val[0]].z != val.z)
nodes[p].min_val[1] = val.id;
if (nodes[p].max_val[0] < val.id)
{
if (nodes[p].max_val[0] != -1 && bi[nodes[p].max_val[0]].z != val.z)
nodes[p].max_val[1] = nodes[p].max_val[0];
nodes[p].max_val[0] = val.id;
}
else if (nodes[p].max_val[1] < val.id && bi[nodes[p].max_val[0]].z != val.z)
nodes[p].max_val[1] = val.id;
if (l == r)
return p;
int mid = (l + r) >> 1;
if (qx <= mid)
nodes[p].lson = update(qx, l, mid, nodes[p].lson, val);
else
nodes[p].rson = update(qx, mid + 1, r, nodes[p].rson, val);
return p;
}
int query(int ql, int qr, int l, int r, int p, package val)
{
if (p == 0)
return 0;
if (ql <= l && r <= qr)
{
int min_val, max_val;
if (nodes[p].min_val[0] == INF)
return 0;
min_val = (val.z == bi[nodes[p].min_val[0]].z) ? nodes[p].min_val[1] : nodes[p].min_val[0];
max_val = (val.z == bi[nodes[p].max_val[0]].z) ? nodes[p].max_val[1] : nodes[p].max_val[0];
if (min_val == INF || max_val == -1)
return 0;
return max(abs(val.id - min_val), abs(val.id - max_val));
}
int mid = (l + r) >> 1, ret = 0;
if (ql <= mid)
ret = max(ret, query(ql, qr, l, mid, nodes[p].lson, val));
if (mid < qr)
ret = max(ret, query(ql, qr, mid + 1, r, nodes[p].rson, val));
return ret;
}
int main()
{
scanf("%d%s", &n, str);
for (int i = 0, ptr = 0; i < n; i++)
{
if (str[i] != str[ptr])
ptr = i;
ans = max(ans, i - ptr + 1);
}
for (int i = 1; i <= n; i++)
{
pre[i] = pre[i - 1];
if (str[i - 1] == 'C')
pre[i].x++;
if (str[i - 1] == 'B')
pre[i].y++;
if (str[i - 1] == 'S')
pre[i].z++;
}
int lower = 0;
for (int i = 1; i <= n; i++)
{
ai[i].x = pre[i].x - pre[i].y;
ai[i].y = pre[i].x - pre[i].z;
ai[i].z = pre[i].y - pre[i].z;
lower = min(lower, min(ai[i].x, min(ai[i].y, ai[i].z)));
ai[i].id = i;
}
n++;
for (int i = 1; i <= n; i++)
ai[i].x -= lower - 1, ai[i].y -= lower - 1, ai[i].z -= lower - 1;
for (int i = 1; i <= n; i++)
bi[i] = ai[i];
bi[0] = bi[n], sort(ai + 1, ai + 1 + n);
int domain = n - lower + 1;
for (int i = 1, ptr = 1; i <= n; i++)
{
if (ai[i].x != ai[ptr].x)
ptr = i;
if (ai[i].x != ai[i + 1].x)
{
for (int j = ptr; j <= i; j++)
ans = max(ans, max(query(1, ai[j].y - 1, 1, domain, 1, ai[j]), query(ai[j].y + 1, domain, 1, domain, 1, ai[j])));
for (int j = ptr; j <= i; j++)
update(ai[j].y, 1, domain, 1, ai[j]);
}
}
printf("%d\n", ans);
return 0;
}
// P3590.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200, INF = 0x3f3f3f3f;
int n, ans, ptot = 1;
char str[MAX_N];
struct node
{
int lson, rson, max_val[2] = {-1, -1}, min_val[2] = {INF, INF};
} nodes[MAX_N * 3];
struct package
{
int id, x, y, z;
bool operator<(const package &rhs) const { return x < rhs.x; }
} pre[MAX_N], ai[MAX_N], bi[MAX_N];
int update(int qx, int l, int r, int p, package val)
{
if (p == 0)
p = ++ptot;
if (nodes[p].min_val[0] > val.id)
{
if (nodes[p].min_val[0] != INF && bi[nodes[p].min_val[0]].id != val.z)
nodes[p].min_val[1] = nodes[p].min_val[0];
nodes[p].min_val[0] = val.id;
}
else if (nodes[p].min_val[1] > val.id && bi[nodes[p].min_val[0]].z != val.z)
nodes[p].min_val[1] = val.id;
if (nodes[p].max_val[0] < val.id)
{
if (nodes[p].max_val[0] != -1 && bi[nodes[p].max_val[0]].z != val.z)
nodes[p].max_val[1] = nodes[p].max_val[0];
nodes[p].max_val[0] = val.id;
}
else if (nodes[p].max_val[1] < val.id && bi[nodes[p].max_val[0]].z != val.z)
nodes[p].max_val[1] = val.id;
if (l == r)
return p;
int mid = (l + r) >> 1;
if (qx <= mid)
nodes[p].lson = update(qx, l, mid, nodes[p].lson, val);
else
nodes[p].rson = update(qx, mid + 1, r, nodes[p].rson, val);
return p;
}
int query(int ql, int qr, int l, int r, int p, package val)
{
if (p == 0)
return 0;
if (ql <= l && r <= qr)
{
int min_val, max_val;
if (nodes[p].min_val[0] == INF)
return 0;
min_val = (val.z == bi[nodes[p].min_val[0]].z) ? nodes[p].min_val[1] : nodes[p].min_val[0];
max_val = (val.z == bi[nodes[p].max_val[0]].z) ? nodes[p].max_val[1] : nodes[p].max_val[0];
if (min_val == INF || max_val == -1)
return 0;
return max(abs(val.id - min_val), abs(val.id - max_val));
}
int mid = (l + r) >> 1, ret = 0;
if (ql <= mid)
ret = max(ret, query(ql, qr, l, mid, nodes[p].lson, val));
if (mid < qr)
ret = max(ret, query(ql, qr, mid + 1, r, nodes[p].rson, val));
return ret;
}
int main()
{
scanf("%d%s", &n, str);
for (int i = 0, ptr = 0; i < n; i++)
{
if (str[i] != str[ptr])
ptr = i;
ans = max(ans, i - ptr + 1);
}
for (int i = 1; i <= n; i++)
{
pre[i] = pre[i - 1];
if (str[i - 1] == 'C')
pre[i].x++;
if (str[i - 1] == 'B')
pre[i].y++;
if (str[i - 1] == 'S')
pre[i].z++;
}
int lower = 0;
for (int i = 1; i <= n; i++)
{
ai[i].x = pre[i].x - pre[i].y;
ai[i].y = pre[i].x - pre[i].z;
ai[i].z = pre[i].y - pre[i].z;
lower = min(lower, min(ai[i].x, min(ai[i].y, ai[i].z)));
ai[i].id = i;
}
n++;
for (int i = 1; i <= n; i++)
ai[i].x -= lower - 1, ai[i].y -= lower - 1, ai[i].z -= lower - 1;
for (int i = 1; i <= n; i++)
bi[i] = ai[i];
bi[0] = bi[n], sort(ai + 1, ai + 1 + n);
int domain = n - lower + 1;
for (int i = 1, ptr = 1; i <= n; i++)
{
if (ai[i].x != ai[ptr].x)
ptr = i;
if (ai[i].x != ai[i + 1].x)
{
for (int j = ptr; j <= i; j++)
ans = max(ans, max(query(1, ai[j].y - 1, 1, domain, 1, ai[j]), query(ai[j].y + 1, domain, 1, domain, 1, ai[j])));
for (int j = ptr; j <= i; j++)
update(ai[j].y, 1, domain, 1, ai[j]);
}
}
printf("%d\n", ans);
return 0;
}
「POI2009」LYZ
之前没学过 Hall 定理,后面发现结论还算是比较显然的:对于任意的左部点集 \(U\),与之相连的极大右部点集 \(S\) 要满足 \(|U| \leq |S|\)。本题在数据范围小的时候显然可以直接二分图匹配做,但是现在的数据并不允许,并要求维护完美匹配性。首先发现最糟情况时存在一个区间 \([l, r]\) 满足:
\[ \sum_{i = l}^r X_i > (r – l + 1 + d) k \]
移项得到:
\[ \sum_{i = l}^r (X_i – k) > d \times k \]
线段树找一段这样的即可。
const int MAX_N = 5e5 + 200;
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
nodes[p].sum = nodes[lson].sum + nodes[rson].sum;
nodes[p].lft = max(nodes[lson].lft, nodes[lson].sum + nodes[rson].lft);
nodes[p].rig = max(nodes[rson].rig, nodes[rson].sum + nodes[lson].rig);
nodes[p].seg = max(nodes[lson].rig + nodes[rson].lft, max(nodes[lson].seg, nodes[rson].seg));
void build(int l, int r, int p)
nodes[p] = node{0, 0, -k, -k};
build(l, mid, lson), build(mid + 1, r, rson);
void update(int qx, int l, int r, int p, int val)
nodes[p].sum += val, nodes[p].seg += val;
nodes[p].lft = nodes[p].rig = max(0LL, nodes[p].sum);
update(qx, l, mid, lson, val);
update(qx, mid + 1, r, rson, val);
scanf("%d%d%d%d", &n, &m, &k, &d), build(1, n, 1);
for (int i = 1; i <= m; i++)
scanf("%d%d", &xpos, &val), update(xpos, 1, n, 1, val);
puts(nodes[1].seg <= 1LL * d * k ? "TAK" : "NIE");
// P3488.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 5e5 + 200;
typedef long long ll;
int n, m, k, d;
struct node
{
ll lft, rig, sum, seg;
} nodes[MAX_N << 2];
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
void pushup(int p)
{
nodes[p].sum = nodes[lson].sum + nodes[rson].sum;
nodes[p].lft = max(nodes[lson].lft, nodes[lson].sum + nodes[rson].lft);
nodes[p].rig = max(nodes[rson].rig, nodes[rson].sum + nodes[lson].rig);
nodes[p].seg = max(nodes[lson].rig + nodes[rson].lft, max(nodes[lson].seg, nodes[rson].seg));
}
void build(int l, int r, int p)
{
if (l == r)
{
nodes[p] = node{0, 0, -k, -k};
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p);
}
void update(int qx, int l, int r, int p, int val)
{
if (l == r)
{
nodes[p].sum += val, nodes[p].seg += val;
nodes[p].lft = nodes[p].rig = max(0LL, nodes[p].sum);
return;
}
if (qx <= mid)
update(qx, l, mid, lson, val);
else
update(qx, mid + 1, r, rson, val);
pushup(p);
}
#undef mid
#undef rson
#undef lson
int main()
{
scanf("%d%d%d%d", &n, &m, &k, &d), build(1, n, 1);
for (int i = 1; i <= m; i++)
{
int xpos, val;
scanf("%d%d", &xpos, &val), update(xpos, 1, n, 1, val);
puts(nodes[1].seg <= 1LL * d * k ? "TAK" : "NIE");
}
return 0;
}
// P3488.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 5e5 + 200;
typedef long long ll;
int n, m, k, d;
struct node
{
ll lft, rig, sum, seg;
} nodes[MAX_N << 2];
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
void pushup(int p)
{
nodes[p].sum = nodes[lson].sum + nodes[rson].sum;
nodes[p].lft = max(nodes[lson].lft, nodes[lson].sum + nodes[rson].lft);
nodes[p].rig = max(nodes[rson].rig, nodes[rson].sum + nodes[lson].rig);
nodes[p].seg = max(nodes[lson].rig + nodes[rson].lft, max(nodes[lson].seg, nodes[rson].seg));
}
void build(int l, int r, int p)
{
if (l == r)
{
nodes[p] = node{0, 0, -k, -k};
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p);
}
void update(int qx, int l, int r, int p, int val)
{
if (l == r)
{
nodes[p].sum += val, nodes[p].seg += val;
nodes[p].lft = nodes[p].rig = max(0LL, nodes[p].sum);
return;
}
if (qx <= mid)
update(qx, l, mid, lson, val);
else
update(qx, mid + 1, r, rson, val);
pushup(p);
}
#undef mid
#undef rson
#undef lson
int main()
{
scanf("%d%d%d%d", &n, &m, &k, &d), build(1, n, 1);
for (int i = 1; i <= m; i++)
{
int xpos, val;
scanf("%d%d", &xpos, &val), update(xpos, 1, n, 1, val);
puts(nodes[1].seg <= 1LL * d * k ? "TAK" : "NIE");
}
return 0;
}
「POI2014」KAR
想起在纪中做过的一道 A 组 SB 题,跟这个比较一致。发现区间之间可以直接维护,那么就上个线段树就好了。
#pragma GCC optimize("Ofast")
const int MAX_N = 4e5 + 200;
bool nodes[MAX_N << 2][2][2];
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p, int l, int r)
nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
for (register int a = 0; a < 2; a++)
for (register int b = 0; b < 2; b++)
for (register int c = 0; c < 2; c++)
for (register int d = 0; d < 2; d++)
nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
inline void update(int qx, int l, int r, int p)
update(qx, l, mid, lson);
update(qx, mid + 1, r, rson);
inline void build(int l, int r, int p)
nodes[p][0][0] = nodes[p][1][1] = true;
build(l, mid, lson), build(mid + 1, r, rson);
for (register int i = 1; i <= n; i++)
ai[i][0] = read(), ai[i][1] = read();
q = read(), build(1, n, 1);
int x = read(), y = read();
swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
update(x, 1, n, 1), update(y, 1, n, 1);
puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
// P3569.cpp
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 4e5 + 200;
int n, ai[MAX_N][2], q;
bool nodes[MAX_N << 2][2][2];
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p, int l, int r)
{
nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
for (register int a = 0; a < 2; a++)
for (register int b = 0; b < 2; b++)
for (register int c = 0; c < 2; c++)
for (register int d = 0; d < 2; d++)
nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
}
inline void update(int qx, int l, int r, int p)
{
if (l == r)
return;
if (qx <= mid)
update(qx, l, mid, lson);
else
update(qx, mid + 1, r, rson);
pushup(p, l, r);
}
inline void build(int l, int r, int p)
{
if (l == r)
{
nodes[p][0][0] = nodes[p][1][1] = true;
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p, l, r);
}
#undef mid
#undef rson
#undef lson
int main()
{
n = read();
for (register int i = 1; i <= n; i++)
ai[i][0] = read(), ai[i][1] = read();
q = read(), build(1, n, 1);
while (q--)
{
int x = read(), y = read();
swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
update(x, 1, n, 1), update(y, 1, n, 1);
puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
}
return 0;
}
// P3569.cpp
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 4e5 + 200;
int n, ai[MAX_N][2], q;
bool nodes[MAX_N << 2][2][2];
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p, int l, int r)
{
nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
for (register int a = 0; a < 2; a++)
for (register int b = 0; b < 2; b++)
for (register int c = 0; c < 2; c++)
for (register int d = 0; d < 2; d++)
nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
}
inline void update(int qx, int l, int r, int p)
{
if (l == r)
return;
if (qx <= mid)
update(qx, l, mid, lson);
else
update(qx, mid + 1, r, rson);
pushup(p, l, r);
}
inline void build(int l, int r, int p)
{
if (l == r)
{
nodes[p][0][0] = nodes[p][1][1] = true;
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p, l, r);
}
#undef mid
#undef rson
#undef lson
int main()
{
n = read();
for (register int i = 1; i <= n; i++)
ai[i][0] = read(), ai[i][1] = read();
q = read(), build(1, n, 1);
while (q--)
{
int x = read(), y = read();
swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
update(x, 1, n, 1), update(y, 1, n, 1);
puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
}
return 0;
}
「POI2014」KLO
我们考虑相间而放,用一个堆以大小为关键字来维护可选项。注意的是,我们尽量把和末尾颜色相同的 block 放前。每次选出最大的块、或者是次大的块放置,然后再 check 即可。
#pragma GCC optimize("Ofast")
const int MAX_N = 4e5 + 200;
bool nodes[MAX_N << 2][2][2];
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p, int l, int r)
nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
for (register int a = 0; a < 2; a++)
for (register int b = 0; b < 2; b++)
for (register int c = 0; c < 2; c++)
for (register int d = 0; d < 2; d++)
nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
inline void update(int qx, int l, int r, int p)
update(qx, l, mid, lson);
update(qx, mid + 1, r, rson);
inline void build(int l, int r, int p)
nodes[p][0][0] = nodes[p][1][1] = true;
build(l, mid, lson), build(mid + 1, r, rson);
for (register int i = 1; i <= n; i++)
ai[i][0] = read(), ai[i][1] = read();
q = read(), build(1, n, 1);
int x = read(), y = read();
swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
update(x, 1, n, 1), update(y, 1, n, 1);
puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
// P3569.cpp
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 4e5 + 200;
int n, ai[MAX_N][2], q;
bool nodes[MAX_N << 2][2][2];
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p, int l, int r)
{
nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
for (register int a = 0; a < 2; a++)
for (register int b = 0; b < 2; b++)
for (register int c = 0; c < 2; c++)
for (register int d = 0; d < 2; d++)
nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
}
inline void update(int qx, int l, int r, int p)
{
if (l == r)
return;
if (qx <= mid)
update(qx, l, mid, lson);
else
update(qx, mid + 1, r, rson);
pushup(p, l, r);
}
inline void build(int l, int r, int p)
{
if (l == r)
{
nodes[p][0][0] = nodes[p][1][1] = true;
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p, l, r);
}
#undef mid
#undef rson
#undef lson
int main()
{
n = read();
for (register int i = 1; i <= n; i++)
ai[i][0] = read(), ai[i][1] = read();
q = read(), build(1, n, 1);
while (q--)
{
int x = read(), y = read();
swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
update(x, 1, n, 1), update(y, 1, n, 1);
puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
}
return 0;
}
// P3569.cpp
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 4e5 + 200;
int n, ai[MAX_N][2], q;
bool nodes[MAX_N << 2][2][2];
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p, int l, int r)
{
nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
for (register int a = 0; a < 2; a++)
for (register int b = 0; b < 2; b++)
for (register int c = 0; c < 2; c++)
for (register int d = 0; d < 2; d++)
nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
}
inline void update(int qx, int l, int r, int p)
{
if (l == r)
return;
if (qx <= mid)
update(qx, l, mid, lson);
else
update(qx, mid + 1, r, rson);
pushup(p, l, r);
}
inline void build(int l, int r, int p)
{
if (l == r)
{
nodes[p][0][0] = nodes[p][1][1] = true;
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p, l, r);
}
#undef mid
#undef rson
#undef lson
int main()
{
n = read();
for (register int i = 1; i <= n; i++)
ai[i][0] = read(), ai[i][1] = read();
q = read(), build(1, n, 1);
while (q--)
{
int x = read(), y = read();
swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
update(x, 1, n, 1), update(y, 1, n, 1);
puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
}
return 0;
}
「POI2010」Monotonicity
首先我们可以把符号序列给倍长出来,然后再考虑用子序列匹配那一套进行 DP。而这里只需要单维,也就是说我们并不记录子序列的长度,因为可以注意到最长的答案中间切掉,也是满足最优子结构的(证明),所以可以不用记录,搞个树状数组就完事了。
const int MAX_N = 1e6 + 200, MAX_M = 5e6 + 200;
int n, m, ai[MAX_N], nodes[3][MAX_M], dp[MAX_N];
inline int lowbit(int x) { return x & (-x); }
void update(int idx, int x, int d)
for (; x < MAX_M; x += lowbit(x))
nodes[idx][x] = max(nodes[idx][x], d);
int query(int idx, int x, int ret = 0)
for (; x; x -= lowbit(x))
ret = max(ret, nodes[idx][x]);
for (int i = 1; i <= n; i++)
for (int i = 1; i <= m; i++)
scanf("%s", tmp), str[i] = tmp[0];
for (int i = m + 1; i <= n; i++)
str[i] = str[(i - 1) % m + 1];
for (int i = 1; i <= n; i++)
dp[i] = max(nodes[2][ai[i]], max(query(0, ai[i] - 1), query(1, MAX_M - ai[i]))) + 1;
nodes[2][ai[i]] = max(nodes[2][ai[i]], dp[i]);
else if (str[dp[i]] == '<')
update(1, MAX_M - ai[i] + 1, dp[i]);
// BZ2090.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200, MAX_M = 5e6 + 200;
int n, m, ai[MAX_N], nodes[3][MAX_M], dp[MAX_N];
char str[MAX_N];
inline int lowbit(int x) { return x & (-x); }
void update(int idx, int x, int d)
{
for (; x < MAX_M; x += lowbit(x))
nodes[idx][x] = max(nodes[idx][x], d);
}
int query(int idx, int x, int ret = 0)
{
for (; x; x -= lowbit(x))
ret = max(ret, nodes[idx][x]);
return ret;
}
int main()
{
char tmp[2];
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &ai[i]);
for (int i = 1; i <= m; i++)
scanf("%s", tmp), str[i] = tmp[0];
for (int i = m + 1; i <= n; i++)
str[i] = str[(i - 1) % m + 1];
int ans = 0;
for (int i = 1; i <= n; i++)
{
dp[i] = max(nodes[2][ai[i]], max(query(0, ai[i] - 1), query(1, MAX_M - ai[i]))) + 1;
ans = max(ans, dp[i]);
if (str[dp[i]] == '=')
nodes[2][ai[i]] = max(nodes[2][ai[i]], dp[i]);
else if (str[dp[i]] == '<')
update(0, ai[i], dp[i]);
else
update(1, MAX_M - ai[i] + 1, dp[i]);
}
printf("%d\n", ans);
return 0;
}
// BZ2090.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200, MAX_M = 5e6 + 200;
int n, m, ai[MAX_N], nodes[3][MAX_M], dp[MAX_N];
char str[MAX_N];
inline int lowbit(int x) { return x & (-x); }
void update(int idx, int x, int d)
{
for (; x < MAX_M; x += lowbit(x))
nodes[idx][x] = max(nodes[idx][x], d);
}
int query(int idx, int x, int ret = 0)
{
for (; x; x -= lowbit(x))
ret = max(ret, nodes[idx][x]);
return ret;
}
int main()
{
char tmp[2];
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &ai[i]);
for (int i = 1; i <= m; i++)
scanf("%s", tmp), str[i] = tmp[0];
for (int i = m + 1; i <= n; i++)
str[i] = str[(i - 1) % m + 1];
int ans = 0;
for (int i = 1; i <= n; i++)
{
dp[i] = max(nodes[2][ai[i]], max(query(0, ai[i] - 1), query(1, MAX_M - ai[i]))) + 1;
ans = max(ans, dp[i]);
if (str[dp[i]] == '=')
nodes[2][ai[i]] = max(nodes[2][ai[i]], dp[i]);
else if (str[dp[i]] == '<')
update(0, ai[i], dp[i]);
else
update(1, MAX_M - ai[i] + 1, dp[i]);
}
printf("%d\n", ans);
return 0;
}
「POI2005」DWA-Two Parties
这道题就很骚了。
首先有个结论,就是一定能找出一个划分方案,使得某个集合中所有的点都连上了偶数条边,且是最优解。知道这个,我们可以尝试给每个点表一个状态 \(x_i\),代表其集合 ID(0/1)。这样我们可以搞成一个异或方程组,然后高斯消元得到一个方案即可。
int n, deg[MAX_N], mat[MAX_N][MAX_N];
for (int i = 1, tot, v; i <= n; i++)
scanf("%d", &v), mat[i][v] = 1, deg[i]++;
mat[i][i] = mat[i][n + 1] = 1;
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
for (int j = i; j <= n + 1; j++)
swap(mat[i][j], mat[key][j]);
for (int j = i + 1; j <= n; j++)
for (int k = i; k <= n + 1; k++)
for (int i = n - 1; i >= 1; i--)
for (int j = i + 1; j <= n; j++)
for (int k = j; k <= n + 1; k++)
for (int i = 1; i <= n; i++)
for (int i = 1; i <= n; i++)
// P3429.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 220;
int n, deg[MAX_N], mat[MAX_N][MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1, tot, v; i <= n; i++)
{
scanf("%d", &tot);
while (tot--)
scanf("%d", &v), mat[i][v] = 1, deg[i]++;
if (deg[i] & 1)
mat[i][i] = mat[i][n + 1] = 1;
}
for (int i = 1; i <= n; i++)
{
int key = i;
for (int j = i + 1; j <= n; j++)
if (mat[j][i] != 0)
{
key = j;
break;
}
if (key != i)
for (int j = i; j <= n + 1; j++)
swap(mat[i][j], mat[key][j]);
for (int j = i + 1; j <= n; j++)
if (mat[j][i] == 1)
for (int k = i; k <= n + 1; k++)
mat[j][k] ^= mat[i][k];
}
mat[n][n] = 1;
// reverse;
for (int i = n - 1; i >= 1; i--)
{
for (int j = i + 1; j <= n; j++)
if (mat[i][j] != 0)
for (int k = j; k <= n + 1; k++)
mat[i][k] ^= mat[j][k];
mat[i][i] = 1;
}
int tot = 0;
for (int i = 1; i <= n; i++)
tot += mat[i][n + 1];
printf("%d\n", tot);
for (int i = 1; i <= n; i++)
if (mat[i][n + 1])
printf("%d ", i);
puts("");
return 0;
}
// P3429.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 220;
int n, deg[MAX_N], mat[MAX_N][MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1, tot, v; i <= n; i++)
{
scanf("%d", &tot);
while (tot--)
scanf("%d", &v), mat[i][v] = 1, deg[i]++;
if (deg[i] & 1)
mat[i][i] = mat[i][n + 1] = 1;
}
for (int i = 1; i <= n; i++)
{
int key = i;
for (int j = i + 1; j <= n; j++)
if (mat[j][i] != 0)
{
key = j;
break;
}
if (key != i)
for (int j = i; j <= n + 1; j++)
swap(mat[i][j], mat[key][j]);
for (int j = i + 1; j <= n; j++)
if (mat[j][i] == 1)
for (int k = i; k <= n + 1; k++)
mat[j][k] ^= mat[i][k];
}
mat[n][n] = 1;
// reverse;
for (int i = n - 1; i >= 1; i--)
{
for (int j = i + 1; j <= n; j++)
if (mat[i][j] != 0)
for (int k = j; k <= n + 1; k++)
mat[i][k] ^= mat[j][k];
mat[i][i] = 1;
}
int tot = 0;
for (int i = 1; i <= n; i++)
tot += mat[i][n + 1];
printf("%d\n", tot);
for (int i = 1; i <= n; i++)
if (mat[i][n + 1])
printf("%d ", i);
puts("");
return 0;
}
「POI2012」STU-Well
大概思路:首先二分那个差值,然后我们再来算每个位置归零的代价,再找最小的位置即可。
那么我们如何快速计算每个位置归零的代价呢?首先我们可以计算让全局合法的最小代价,方式是正反各扫一遍,保证 \(|a_i – a_{i + 1}| \leq mid\)。枚举 \(k\) 时,我们可以分左右来算贡献。以左侧为例,找到一个位置 \(a_{L} > (k – L)mid\),那么 \([L, i – 1]\) 这一部分的和减去等差数列之和就是部分贡献了。我想了一会为什么这样是对的,发现:如果 \(a_{L} > (k – L)mid\),且即使这段区间不是等差的,那么这段区间和减去等差数列之和,「多扣」的部分会从 \(a_L\) 上扣除。右侧原理一致。
const int MAX_N = 1e6 + 200;
ll m, xi[MAX_N], ai[MAX_N], pre[MAX_N], prefix[MAX_N], suffix[MAX_N];
for (int i = 2; i <= n; i++)
ai[i] = min(ai[i - 1] + mid, xi[i]);
for (int i = n - 1; i >= 1; i--)
ai[i] = min(ai[i + 1] + mid, ai[i]);
for (int i = 1; i <= n; i++)
acc += xi[i] - ai[i], pre[i] = pre[i - 1] + ai[i];
for (int i = 1, ptr = 1; i <= n; i++)
while (ptr < i && ai[ptr] <= 1LL * (i - ptr) * mid)
prefix[i] = pre[i - 1] - pre[ptr - 1] - 1LL * (i - ptr) * (i - ptr + 1) / 2 * mid;
for (int i = n, ptr = n; i >= 1; i--)
while (ptr > i && ai[ptr] <= 1LL * (ptr - i) * mid)
suffix[i] = pre[ptr] - pre[i] - 1LL * (ptr - i) * (ptr - i + 1) / 2 * mid;
for (int i = 1; i <= n; i++)
if (prefix[i] + suffix[i] + acc + ai[i] <= m)
for (int i = 1; i <= n; i++)
int l = 0, r = 1e9, res = 0;
printf("%d %d\n", check(res), res);
// P3534.cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX_N = 1e6 + 200;
int n;
ll m, xi[MAX_N], ai[MAX_N], pre[MAX_N], prefix[MAX_N], suffix[MAX_N];
int check(int mid)
{
ai[1] = xi[1];
for (int i = 2; i <= n; i++)
ai[i] = min(ai[i - 1] + mid, xi[i]);
for (int i = n - 1; i >= 1; i--)
ai[i] = min(ai[i + 1] + mid, ai[i]);
ll acc = 0;
for (int i = 1; i <= n; i++)
acc += xi[i] - ai[i], pre[i] = pre[i - 1] + ai[i];
if (acc > m)
return 0;
for (int i = 1, ptr = 1; i <= n; i++)
{
while (ptr < i && ai[ptr] <= 1LL * (i - ptr) * mid)
ptr++;
prefix[i] = pre[i - 1] - pre[ptr - 1] - 1LL * (i - ptr) * (i - ptr + 1) / 2 * mid;
}
for (int i = n, ptr = n; i >= 1; i--)
{
while (ptr > i && ai[ptr] <= 1LL * (ptr - i) * mid)
ptr--;
suffix[i] = pre[ptr] - pre[i] - 1LL * (ptr - i) * (ptr - i + 1) / 2 * mid;
}
for (int i = 1; i <= n; i++)
if (prefix[i] + suffix[i] + acc + ai[i] <= m)
return i;
return 0;
}
int main()
{
scanf("%d%lld", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%lld", &xi[i]);
int l = 0, r = 1e9, res = 0;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid))
r = mid - 1, res = mid;
else
l = mid + 1;
}
printf("%d %d\n", check(res), res);
return 0;
}
// P3534.cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX_N = 1e6 + 200;
int n;
ll m, xi[MAX_N], ai[MAX_N], pre[MAX_N], prefix[MAX_N], suffix[MAX_N];
int check(int mid)
{
ai[1] = xi[1];
for (int i = 2; i <= n; i++)
ai[i] = min(ai[i - 1] + mid, xi[i]);
for (int i = n - 1; i >= 1; i--)
ai[i] = min(ai[i + 1] + mid, ai[i]);
ll acc = 0;
for (int i = 1; i <= n; i++)
acc += xi[i] - ai[i], pre[i] = pre[i - 1] + ai[i];
if (acc > m)
return 0;
for (int i = 1, ptr = 1; i <= n; i++)
{
while (ptr < i && ai[ptr] <= 1LL * (i - ptr) * mid)
ptr++;
prefix[i] = pre[i - 1] - pre[ptr - 1] - 1LL * (i - ptr) * (i - ptr + 1) / 2 * mid;
}
for (int i = n, ptr = n; i >= 1; i--)
{
while (ptr > i && ai[ptr] <= 1LL * (ptr - i) * mid)
ptr--;
suffix[i] = pre[ptr] - pre[i] - 1LL * (ptr - i) * (ptr - i + 1) / 2 * mid;
}
for (int i = 1; i <= n; i++)
if (prefix[i] + suffix[i] + acc + ai[i] <= m)
return i;
return 0;
}
int main()
{
scanf("%d%lld", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%lld", &xi[i]);
int l = 0, r = 1e9, res = 0;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid))
r = mid - 1, res = mid;
else
l = mid + 1;
}
printf("%d %d\n", check(res), res);
return 0;
}
「POI2014」PAN-Solar Panels
题目大概就是要求你在二维平面上,找到一个最大的 \(d\) 使得刚好 \(x = kd, y = kd\) 在这个矩形内有交点。发现有交点的条件是:
\[ \lfloor \frac{smax}{d} \rfloor – \lfloor \frac{smin – 1}{d} \rfloor > 0 \\ \lfloor \frac{wmax}{d} \rfloor – \lfloor \frac{wmin – 1}{d} \rfloor > 0 \]
那可以直接搞搞整除分块,每次取右端点做答案即可。
int T, smin, smax, wmin, wmax;
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
smin = read(), smax = read(), wmin = read(), wmax = read();
for (int d = 1, gx; d <= min(smax, wmax); d = gx + 1)
gx = min({smax / (smax / d), wmax / (wmax / d)});
gx = min(gx, smin / (smin / d));
gx = min(gx, wmin / (wmin / d));
if ((smax / d) - (smin / d) > 0 && (wmax / d) - (wmin / d) > 0)
// P3579.cpp
#include <bits/stdc++.h>
using namespace std;
int T, smin, smax, wmin, wmax;
inline char nc()
{
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
int main()
{
scanf("%d", &T);
while (T--)
{
smin = read(), smax = read(), wmin = read(), wmax = read();
smin--, wmin--;
int ans = 0;
for (int d = 1, gx; d <= min(smax, wmax); d = gx + 1)
{
gx = min({smax / (smax / d), wmax / (wmax / d)});
if (int(smin / d) != 0)
gx = min(gx, smin / (smin / d));
if (int(wmin / d) != 0)
gx = min(gx, wmin / (wmin / d));
if ((smax / d) - (smin / d) > 0 && (wmax / d) - (wmin / d) > 0)
ans = gx;
}
printf("%d\n", ans);
}
return 0;
}
// P3579.cpp
#include <bits/stdc++.h>
using namespace std;
int T, smin, smax, wmin, wmax;
inline char nc()
{
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
int main()
{
scanf("%d", &T);
while (T--)
{
smin = read(), smax = read(), wmin = read(), wmax = read();
smin--, wmin--;
int ans = 0;
for (int d = 1, gx; d <= min(smax, wmax); d = gx + 1)
{
gx = min({smax / (smax / d), wmax / (wmax / d)});
if (int(smin / d) != 0)
gx = min(gx, smin / (smin / d));
if (int(wmin / d) != 0)
gx = min(gx, wmin / (wmin / d));
if ((smax / d) - (smin / d) > 0 && (wmax / d) - (wmin / d) > 0)
ans = gx;
}
printf("%d\n", ans);
}
return 0;
}
「POI2015」PUS
经典的线段树优化建图,暴力拆成 \(k + 1\) 个区间之后跑 DAG DP 即可。
const int MAX_N = 6e5 + 200, MAX_E = 8e6 + 200;
int n, s, m, dp[MAX_N], head[MAX_N], current, sidx[MAX_N], ptot, deg[MAX_N], topoidx[MAX_N], topotot;
void addpath(int src, int dst, int weight)
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].weight = weight, head[src] = current++, deg[dst]++;
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
void build(int l, int r, int p)
return (void)(sidx[l] = p);
addpath(p, lson, 0), addpath(p, rson, 0);
build(l, mid, lson), build(mid + 1, r, rson);
void update(int ql, int qr, int l, int r, int p, int src)
return (void)(addpath(src, p, 0));
update(ql, qr, l, mid, lson, src);
update(ql, qr, mid + 1, r, rson, src);
memset(head, -1, sizeof(head));
scanf("%d%d%d", &n, &s, &m), build(1, n, 1);
for (int i = 1; i <= n; i++)
for (int i = 1, p, d; i <= s; i++)
scanf("%d%d", &p, &d), dp[sidx[p]] = d, isFixed[sidx[p]] = true;
int l, r, k, cpt, last = l - 1;
scanf("%d%d%d", &l, &r, &k), cpt = ++ptot, last = l - 1;
for (int i = 1, pt; i <= k; i++)
scanf("%d", &pt), addpath(sidx[pt], cpt, 1), update(last + 1, pt - 1, 1, n, 1, cpt), last = pt;
update(last + 1, r, 1, n, 1, cpt);
for (int i = 1; i <= ptot; i++)
q.pop(), topoidx[++topotot] = u;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (--deg[edges[i].to] == 0)
for (int i = 1; i <= ptot; i++)
for (int id = ptot; id >= 1; id--)
int u = topoidx[id], max_val = 1;
for (int i = head[u]; i != -1; i = edges[i].nxt)
max_val = max(max_val, dp[edges[i].to] + edges[i].weight);
if (isFixed[u] && max_val > dp[u])
for (int i = 1; i <= n; i++)
if (dp[sidx[i]] > 1e9 || dp[sidx[i]] < 1)
for (int i = 1; i <= n; i++)
printf("%d%c", dp[sidx[i]], " \n"[i == n]);
// P3588.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 6e5 + 200, MAX_E = 8e6 + 200;
int n, s, m, dp[MAX_N], head[MAX_N], current, sidx[MAX_N], ptot, deg[MAX_N], topoidx[MAX_N], topotot;
bool isFixed[MAX_N];
struct edge
{
int to, nxt, weight;
} edges[MAX_E];
void addpath(int src, int dst, int weight)
{
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].weight = weight, head[src] = current++, deg[dst]++;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
void build(int l, int r, int p)
{
ptot = max(ptot, p);
if (l == r)
return (void)(sidx[l] = p);
addpath(p, lson, 0), addpath(p, rson, 0);
build(l, mid, lson), build(mid + 1, r, rson);
}
void update(int ql, int qr, int l, int r, int p, int src)
{
if (ql > qr)
return;
if (ql <= l && r <= qr)
return (void)(addpath(src, p, 0));
if (ql <= mid)
update(ql, qr, l, mid, lson, src);
if (mid < qr)
update(ql, qr, mid + 1, r, rson, src);
}
#undef mid
#undef rson
#undef lson
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d%d", &n, &s, &m), build(1, n, 1);
for (int i = 1; i <= n; i++)
dp[sidx[i]] = 1;
for (int i = 1, p, d; i <= s; i++)
scanf("%d%d", &p, &d), dp[sidx[p]] = d, isFixed[sidx[p]] = true;
while (m--)
{
int l, r, k, cpt, last = l - 1;
scanf("%d%d%d", &l, &r, &k), cpt = ++ptot, last = l - 1;
for (int i = 1, pt; i <= k; i++)
scanf("%d", &pt), addpath(sidx[pt], cpt, 1), update(last + 1, pt - 1, 1, n, 1, cpt), last = pt;
update(last + 1, r, 1, n, 1, cpt);
}
queue<int> q;
for (int i = 1; i <= ptot; i++)
if (deg[i] == 0)
q.push(i);
while (!q.empty())
{
int u = q.front();
q.pop(), topoidx[++topotot] = u;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (--deg[edges[i].to] == 0)
q.push(edges[i].to);
}
for (int i = 1; i <= ptot; i++)
if (deg[i] != 0)
puts("NIE"), exit(0);
for (int id = ptot; id >= 1; id--)
{
int u = topoidx[id], max_val = 1;
for (int i = head[u]; i != -1; i = edges[i].nxt)
max_val = max(max_val, dp[edges[i].to] + edges[i].weight);
if (isFixed[u] && max_val > dp[u])
puts("NIE"), exit(0);
else if (!isFixed[u])
dp[u] = max_val;
}
for (int i = 1; i <= n; i++)
if (dp[sidx[i]] > 1e9 || dp[sidx[i]] < 1)
puts("NIE"), exit(0);
puts("TAK");
for (int i = 1; i <= n; i++)
printf("%d%c", dp[sidx[i]], " \n"[i == n]);
return 0;
}
// P3588.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 6e5 + 200, MAX_E = 8e6 + 200;
int n, s, m, dp[MAX_N], head[MAX_N], current, sidx[MAX_N], ptot, deg[MAX_N], topoidx[MAX_N], topotot;
bool isFixed[MAX_N];
struct edge
{
int to, nxt, weight;
} edges[MAX_E];
void addpath(int src, int dst, int weight)
{
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].weight = weight, head[src] = current++, deg[dst]++;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
void build(int l, int r, int p)
{
ptot = max(ptot, p);
if (l == r)
return (void)(sidx[l] = p);
addpath(p, lson, 0), addpath(p, rson, 0);
build(l, mid, lson), build(mid + 1, r, rson);
}
void update(int ql, int qr, int l, int r, int p, int src)
{
if (ql > qr)
return;
if (ql <= l && r <= qr)
return (void)(addpath(src, p, 0));
if (ql <= mid)
update(ql, qr, l, mid, lson, src);
if (mid < qr)
update(ql, qr, mid + 1, r, rson, src);
}
#undef mid
#undef rson
#undef lson
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d%d", &n, &s, &m), build(1, n, 1);
for (int i = 1; i <= n; i++)
dp[sidx[i]] = 1;
for (int i = 1, p, d; i <= s; i++)
scanf("%d%d", &p, &d), dp[sidx[p]] = d, isFixed[sidx[p]] = true;
while (m--)
{
int l, r, k, cpt, last = l - 1;
scanf("%d%d%d", &l, &r, &k), cpt = ++ptot, last = l - 1;
for (int i = 1, pt; i <= k; i++)
scanf("%d", &pt), addpath(sidx[pt], cpt, 1), update(last + 1, pt - 1, 1, n, 1, cpt), last = pt;
update(last + 1, r, 1, n, 1, cpt);
}
queue<int> q;
for (int i = 1; i <= ptot; i++)
if (deg[i] == 0)
q.push(i);
while (!q.empty())
{
int u = q.front();
q.pop(), topoidx[++topotot] = u;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (--deg[edges[i].to] == 0)
q.push(edges[i].to);
}
for (int i = 1; i <= ptot; i++)
if (deg[i] != 0)
puts("NIE"), exit(0);
for (int id = ptot; id >= 1; id--)
{
int u = topoidx[id], max_val = 1;
for (int i = head[u]; i != -1; i = edges[i].nxt)
max_val = max(max_val, dp[edges[i].to] + edges[i].weight);
if (isFixed[u] && max_val > dp[u])
puts("NIE"), exit(0);
else if (!isFixed[u])
dp[u] = max_val;
}
for (int i = 1; i <= n; i++)
if (dp[sidx[i]] > 1e9 || dp[sidx[i]] < 1)
puts("NIE"), exit(0);
puts("TAK");
for (int i = 1; i <= n; i++)
printf("%d%c", dp[sidx[i]], " \n"[i == n]);
return 0;
}