- nowcoder訓練
區間
線段樹板子題,我們只需要把區間每一個點設定成1,然後修改的時候直接改點,然後查區間就行
線段樹維護最大欄位和/ 01 串最大連續 1 的個數模板題。
把白色和黑色看成 1/0 兩個數就行了。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define lc u << 1
#define rc u << 1 | 1
const int N = 1e5 + 5;
i64 w[N], n, m, p;
struct Tree { //線段樹
int l, r;
int sum1, lmax1, rmax1, max1;
int sum0, lmax0, rmax0, max0;
int tag, rev;
} tr[N << 2];
void cal_lazy(int fa, int ch) {
int len = tr[ch].r - tr[ch].l + 1;
if (tr[fa].tag == 0) {
tr[ch].tag = 0, tr[ch].rev = 0;
tr[ch].sum0 = tr[ch].lmax0 = tr[ch].rmax0 = tr[ch].max0 = len;
tr[ch].sum1 = tr[ch].lmax1 = tr[ch].rmax1 = tr[ch].max1 = 0;
}
if (tr[fa].tag == 1) {
tr[ch].tag = 1, tr[ch].rev = 0;
tr[ch].sum0 = tr[ch].lmax0 = tr[ch].rmax0 = tr[ch].max0 = 0;
tr[ch].sum1 = tr[ch].lmax1 = tr[ch].rmax1 = tr[ch].max1 = len;
}
if (tr[fa].rev) {
tr[ch].rev ^= 1;
swap(tr[ch].sum1, tr[ch].sum0);
swap(tr[ch].lmax1, tr[ch].lmax0);
swap(tr[ch].rmax1, tr[ch].rmax0);
swap(tr[ch].max1, tr[ch].max0);
}
}
void tag_union(int fa, int ch) {
tr[ch].tag = tr[fa].tag;
tr[ch].rev ^= tr[fa].rev;
}
void init_lazy(int u) {
tr[u].tag = -1;
tr[u].rev = 0;
}
void pushdown(int u) {
if (tr[u].tag != -1 || tr[u].rev != 0) {
cal_lazy(u, lc);
cal_lazy(u, rc);
// tag_union(u, lc);
// tag_union(u, rc);
init_lazy(u);
}
}
void pushup(int u) { //上傳
tr[u].sum1 = tr[lc].sum1 + tr[rc].sum1;
tr[u].sum0 = tr[lc].sum0 + tr[rc].sum0;
tr[u].lmax1 = tr[lc].lmax1 + (tr[lc].sum0 ? 0 : tr[rc].lmax1);
tr[u].rmax1 = tr[rc].rmax1 + (tr[rc].sum0 ? 0 : tr[lc].rmax1);
tr[u].lmax0 = tr[lc].lmax0 + (tr[lc].sum1 ? 0 : tr[rc].lmax0);
tr[u].rmax0 = tr[rc].rmax0 + (tr[rc].sum1 ? 0 : tr[lc].rmax0);
tr[u].max1 = max({tr[lc].max1, tr[rc].max1, tr[lc].rmax1 + tr[rc].lmax1});
tr[u].max0 = max({tr[lc].max0, tr[rc].max0, tr[lc].rmax0 + tr[rc].lmax0});
}
void build(int u, int l, int r) { //建樹
tr[u].l = l, tr[u].r = r;
init_lazy(u);
if (l == r) {
int t = 1;
tr[u] = {l, r, t, t, t, t, t ^ 1, t ^ 1, t ^ 1, t ^ 1, -1, 0};
return ;
}
int mid = (l + r) >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, int op) {
if (tr[u].l >= l && tr[u].r <= r) {
int len = tr[u].r - tr[u].l + 1;
if (op == 0) {
tr[u].rev = 0, tr[u].tag = 0;
tr[u].sum0 = tr[u].lmax0 = tr[u].rmax0 = tr[u].max0 = len;
tr[u].sum1 = tr[u].lmax1 = tr[u].rmax1 = tr[u].max1 = 0;
} else if (op == 1) {
tr[u].rev = 0, tr[u].tag = 1;
tr[u].sum0 = tr[u].lmax0 = tr[u].rmax0 = tr[u].max0 = 0;
tr[u].sum1 = tr[u].lmax1 = tr[u].rmax1 = tr[u].max1 = len;
} else {
tr[u].rev ^= 1;
swap(tr[u].sum1, tr[u].sum0);
swap(tr[u].lmax1, tr[u].lmax0);
swap(tr[u].rmax1, tr[u].rmax0);
swap(tr[u].max1, tr[u].max0);
}
return ;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid)
modify(lc, l, r, op);
if (r > mid)
modify(rc, l, r, op);
pushup(u);
}
Tree query(int u, int l, int r) { //區查
if (l <= tr[u].l && tr[u].r <= r)
return tr[u];
int mid = tr[u].l + tr[u].r >> 1;
pushdown(u);
if (r <= mid) return query(lc, l, r);
else if (l > mid) return query(rc, l, r);
else {
Tree res, L = query(lc, l, mid), R = query(rc, mid + 1, r);
res.sum1 = L.sum1 + R.sum1;
res.sum0 = L.sum0 + R.sum0;
res.lmax1 = L.lmax1 + (L.sum0 ? 0 : R.lmax1);
res.rmax1 = R.rmax1 + (R.sum0 ? 0 : L.rmax1);
res.lmax0 = L.lmax0 + (L.sum1 ? 0 : R.lmax0);
res.rmax0 = R.rmax0 + (R.sum1 ? 0 : L.rmax0);
res.max1 = max({L.max1, R.max1, L.rmax1 + R.lmax1});
res.max0 = max({L.max0, R.max0, L.rmax0 + R.lmax0});
return res;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,q;
cin >> n >> q;
build(1,1,n);
while(q--){
int op;
cin >> op;
if(op == 1){
int x;
cin >> x;
modify(1,x,x,2);
}else{
int l,r;
cin >> l >> r;
auto ans = query(1,l,r);
cout << ans.max1 << '\n';
}
}
return 0;
}
G-求值
三分,化簡後只有兩個數,然後函式一定是v型的,我們列舉x然後三分y,每次更新最小值即可
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
i64 a, b, c, n, w;
cin >> a >> b >> c >> n >> w;
auto check = [&](i64 mid, i64 x) {
return abs(x * a + mid * b + (n - mid - x) * c - w);
};
i64 ans = LLONG_MAX >> 1;
for (int i = 0; i <= n; i ++) {
int l = 0, r = n - i;
while (l <= r) {
i64 midl = l + (r - l) / 3;
i64 midr = r - (r - l) / 3;
ans = min({ans, check(midl, i), check(midr, i)});
if (check(midl, i) > check(midr, i))
l = midl + 1;
else
r = midr - 1;
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
[wyh的吃雞(https://ac.nowcoder.com/acm/problem/15445)
這道題難在不能標記vis,因為有可能先沒有經過這個點,當車重新走過的時候車經過的時間會更短,所以這道題不能標記vis
但是我們可以這樣去做,開成三維,第三維表示用不用車經過有兩個狀態,不用車經過和用車,不用車經過很簡單就是想標記vis一樣,用車我們需要比較同一級的
一旦用車,後面的情況都是用車的,因為可能用車也存在快慢,不要車也由快慢,最後只剩下兩個狀態,即到終點有沒有用車,然後每次更新時間分成有沒有車去判斷;
最後我們只需要遍歷終點的有無車狀態有沒有解取min即可
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n, t;
char dt[107][107];
int step[107][107][2];
const int dir[4][2] = { {1,0},{-1,0},{0,1}, { 0,-1 } };
struct node {
int x, y;
bool c;
};
int bfs(node st, vector<node> &ed) {
queue<node> q;
q.push(st);
step[st.x][st.y][0] = 0;
while (!q.empty()) {
node cur = q.front();
q.pop();
if (dt[cur.x][cur.y] == 'X') continue;
for (int i = 0;i < 4;i++) {
int xx = cur.x + dir[i][0];
int yy = cur.y + dir[i][1];
int delta = cur.c ? 1 : 2;
if (xx < 0 || xx >= n || yy < 0 || yy >= n || dt[xx][yy] == 'O')continue;
bool cc = cur.c || dt[xx][yy] == 'C';
if (step[xx][yy][cc] <= step[cur.x][cur.y][cur.c] + delta) continue;
///不能用vis鎖定點,因為擴充套件時間線混亂,不按照時間順序擴充套件
///有可能時間晚的車先佔了格子,早的車沒擴充套件過來就無法覆蓋了,因此只能用距離覆蓋
step[xx][yy][cc] = step[cur.x][cur.y][cur.c] + delta;
q.push({ xx,yy,cc });
}
}
int ans = 1e9;
for (auto e : ed) ans = min({ ans, step[e.x][e.y][0],step[e.x][e.y][1] });///目的地是個連通塊
return ans;
}
bool solve() {
cin >> n >> t;
node st;
vector<node> ed;
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
cin >> dt[i][j];
if (dt[i][j] == 'S') st.x = i, st.y = j, st.c = 0;
if (dt[i][j] == 'X') ed.push_back({ i,j,0 });
step[i][j][0] = step[i][j][1] = 1e9;
}
}
int ans = bfs(st, ed);
if (ans > t) return false;
else cout << "YES\n" << ans << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << "NO" << '\n';
}
return 0;
}