做题记录1

P3324 [SDOI2015] 星际战争

思路

如果花费 \(T\) 时间可以消灭所有的机器人,显然大于 \(T\) 的时间也可以。具有单调性,考虑二分答案。

设当前二分的时间为 \(x\) ,对于第 \(i\) 个武器,它能造成的伤害为 \(b_i \times x\) 。设武器所在的集合为 \(L\) ,机器人所在的集合为 \(R\) ,将每个武器和它能攻击到的机器人连一条边,就形成了二分图,因此问题转化为了判断是否满足

\[\sum b_i \times t > \sum a_i \]

可以再连一个流量无限的源点和汇点,用最大流解决这个问题。

具体的建图细节:

对于源点到 \(L\) 到每个点,建一条流量为 \(b_i \times x\) 的边;对于 \(L\)\(R\) 之间的点,建流量为 \(+ \infty\) 的边;对于 \(R\) 的每个点到汇点的点,建一条流量为 \(a_i\) 的边。

代码

#include<bits/stdc++.h>
#define x first
#define y second
using i64 = long long;
using u64 = unsigned long long;
using u128 = __uint128_t;
using PII = std::pair<int, int>;
const int N = 1e5 + 10;
const int M = 1e5 + 10;
const int INF = 1e9;
const double eps = 1e-6;
struct flow {
    int cnt = 1, hd[N], nxt[M * 2], to[M * 2];
    double limit[M * 2];
    void add(int u, int v, double w) {
        nxt[++cnt] = hd[u], hd[u] = cnt, to[cnt] = v, limit[cnt] = w;
        nxt[++cnt] = hd[v], hd[v] = cnt, to[cnt] = u, limit[cnt] = 0;
    }
    int T, dis[N], cur[N];
    double dfs(int id, double res) {
        if(id == T) return res;
        double flow = 0;
        for(int i = cur[id]; i && res > eps; i = nxt[i]) {
            cur[id] = i;
            double c = std::min(res, (double)limit[i]); int it = to[i];
            if(dis[id] + 1 == dis[it] && c > eps) {
                double k = dfs(it, c);
                if(k > eps) {
                    flow += k, res -= k, limit[i] -= k, limit[i ^ 1] += k;
                }
            }
        }
        if(flow <= eps) dis[id] = -1;
        return flow;
    }
    double maxflow(int s, int t) {
        T = t;
        double flow = 0;
        while(1) {
            std::queue<int> q;
            memcpy(cur, hd, sizeof(hd));
            memset(dis, 0xff, sizeof(dis));
            q.push(s), dis[s] = 0;
            while(q.size()) {
                int u = q.front();
                q.pop();
                for(int i = hd[u]; i; i = nxt[i]) {
                    if(dis[to[i]] == -1 && limit[i] > eps) {
                        dis[to[i]] = dis[u] + 1;
                        q.push(to[i]);
                    }
                }
            }
            if(dis[t] == -1) return flow;
            flow += dfs(s, 1e18);
        }
    }
};
void solve(void) {
    int n, m; std::cin >> n >> m;
    std::vector<int> a(n + 1);
    std::vector<int> b(m + 1);
    double sum = 0;
    for(int i = 1; i <= n; i++) {
        std::cin >> a[i];
        sum += a[i];
    }
    for(int i = 1; i <= m; i++) std::cin >> b[i];
    bool st[51][51] = {0};
    for(int i = 1; i <= m; i++) {
        for(int j = 1; j <= n; j++) {
            std::cin >> st[i][j];
        }
    }
    flow g;
    auto check = [&](double x) -> bool {
        g.cnt = 1;
        memset(g.hd, 0, sizeof(g.hd));
        int s = 0;
        int L = 1, R = L + m, t = R + m + n;
        for(int i = 1; i <= m; i++) {
            g.add(s, L + i, (double)b[i] * x);
        }
        for(int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) {
                if(st[i][j]) g.add(L + i, R + j, INF);
            }
        }
        for(int i = 1; i <= n; i++) {
            g.add(R + i, t, a[i]);
        }
        return g.maxflow(s, t) + eps >= sum;
    };
    double l = 0, r = 1e9, ans = -1;
    while(r - l >= eps) {
        double mid = (l + r) / 2;
        if(check(mid)) {
            ans = mid;
            r = mid;
        } else l = mid;
    }
    std::cout << std::fixed << std::setprecision(6) << ans;
}
int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t = 1;
    //std::cin >> t;
    while(t--) solve();
    return 0;
}

P5038 [SCOI2012] 奇怪的游戏

思路

将格子按照奇偶黑白染色,每个格子分别和与它相邻的格子连边,就形成了一张二分图。

设最终变成的数字为 \(x\) ,每个格子变成 \(x\) 的次数就为 \(x - a_{i, j}\) 。在二分图的基础上找一个源点和汇点,源点到白格子的每条边连一条 \(x - a_{i, j}\) 的边,格子和格子之间连一条 \(+ \infty\) 的边,黑格子到汇点连一条 \(x - a_{i, j}\) 的边,在这个图上跑一遍最大流,如果最大流确实等于 \(\sum x - a_{i, j}\) 说明当前的 \(x\) 是可行的。可以发现 \(x\) 具有单调性,因此可以用二分答案的方式找 \(x\)

接下来分情况讨论:

设白点的数量为 \(c_0\) ,初始的数值总和为 \(s_0\) ;黑点的数量为 \(c_1\) ,初始的数值总和为 \(s_1\) 。假设最后要变成 \(x\) ,那么有:

\[c_0 \times x - s_0 = c_1 \times x - s_1 \ \Rightarrow \ (c_0 - c_1) \times x = (s_0 - s_1) \]

  1. 如果 \(c_0 \neq c_1\)\(x\) 不需要二分,可以直接算出来,因此算出来 check 一下就可以了。
  2. 如果 \(c_0 = c1\)
    如果 \(s_0 = s_1\) ,式子没有意义,直接可以确定无解;
    如果 \(s_0 \neq s_1\) ,说明满足要求的 \(x\) 不止一个,用二分答案的方式找到答案。

最后如果有合适的 \(x\) ,那么答案就为 \(x \times c_0 - s_0\)

代码

#include<bits/stdc++.h>
#define x first
#define y second
using i64 = long long;
using u64 = unsigned long long;
using u128 = __uint128_t;
using PII = std::pair<int, int>;
const int N = 10000;
const int M = 30000;
const i64 INF = 1e18;
const double eps = 1e-6;
struct flow {
    int cnt = 1, hd[N], nxt[M * 2], to[M * 2];
    i64 limit[M * 2];
    void add(int u, int v, i64 w) {
        nxt[++cnt] = hd[u], hd[u] = cnt, to[cnt] = v, limit[cnt] = w;
        nxt[++cnt] = hd[v], hd[v] = cnt, to[cnt] = u, limit[cnt] = 0;
    }
    int T, dis[N], cur[N];
    i64 dfs(int id, i64 res) {
        if(id == T) return res;
        i64 flow = 0;
        for(int i = cur[id]; i && res; i = nxt[i]) {
            cur[id] = i;
            i64 c = std::min(res, (i64)limit[i]), it = to[i];
            if(dis[id] + 1 == dis[it] && c) {
                i64 k = dfs(it, c);
                flow += k, res -= k, limit[i] -= k, limit[i ^ 1] += k;
            }
        }
        if(!flow) dis[id] = -1;
        return flow;
    }
    i64 maxflow(int s, int t) {
        T = t;
        i64 flow = 0;
        while(1) {
            std::queue<int> q;
            memcpy(cur, hd, sizeof(hd));
            memset(dis, 0xff, sizeof(dis));
            q.push(s), dis[s] = 0;
            while(q.size()) {
                int u = q.front();
                q.pop();
                for(int i = hd[u]; i; i = nxt[i]) {
                    if(dis[to[i]] == -1 && limit[i]) {
                        dis[to[i]] = dis[u] + 1;
                        q.push(to[i]);
                    }
                }
            }
            if(dis[t] == -1) return flow;
            flow += dfs(s, 1e18);
        }
    }
};
i64 a[45][45];
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
void solve(void) {
    int n, m; std::cin >> n >> m;
    i64 s0 = 0, s1 = 0, c0 = 0, c1 = 0;
    i64 maxn = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            std::cin >> a[i][j]; 
            maxn = std::max(maxn, a[i][j]);
            if((i + j) % 2 == 0) s0 += a[i][j], c0 += 1;
            else s1 += a[i][j], c1 += 1;
        }
    }
    flow g;
    auto check = [&](i64 x) -> bool {
        g.cnt = 1;
        memset(g.hd, 0, sizeof(g.hd));
        if(x < maxn) return false;
        i64 sum = 0;
        int s = 0, t = n * m + 1;
        int v = n * m + 2;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(x - a[i][j] < 0) return false;
                if((i + j) % 2 == 0) {
                    sum += x - a[i][j];
                    g.add(s, (i - 1) * m + j, x - a[i][j]);
                    for(int k = 0; k < 4; k++) {
                        int a = i + dx[k], b = j + dy[k];
                        if(a >= 1 && a <= n && b >= 1 && b <= m) 
                            g.add((i - 1) * m + j, (a - 1) * m + b, INF);
                    }
                }
                else g.add((i - 1) * m + j,  t, x - a[i][j]);
            }
        }
        i64 res = g.maxflow(s, t);
        return res == sum;
    };
    if(c1 != c0) {
        if((s0 - s1) % (c0 - c1)) {
            std::cout << "-1\n";
            return;
        }
        i64 x = (s0 - s1) / (c0 - c1);
        if(check(x)) 
            std::cout << x * c0 - s0 << '\n';
        else std::cout << "-1\n";
        return;
    } else {
        if(s0 != s1) {
            std::cout << "-1\n";
            return;
        }
    }
    i64 l = maxn, r = 1e13, ans = -1;
    while(l <= r) {
        i64 mid = (l + r) / 2;
        if(check(mid)) {
            r = mid - 1;
            ans = mid;
        } else l = mid + 1;
    }
    if(ans < 0) std::cout << -1 << '\n';
    else std::cout << ans * c0 - s0 << '\n';
}
int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t = 1;
    std::cin >> t;
    while(t--) solve();
    return 0;
}

P3163 [CQOI2014] 危桥

思路

一个多源网络流的trick,交换建图。

先根据岛与岛之间的关系建图,之后将图复制两份。

第一次 \(S \rightarrow a1\)\(S \rightarrow b1\)\(a2 \rightarrow T\)\(b2 \rightarrow T\)

第二次 \(S \rightarrow a1\)\(S \rightarrow b2\)\(a2 \rightarrow T\)\(b1 \rightarrow T\)

对两张图跑最大流,当且仅当两张图的最大流都为 \(2 \times (a_n + b_n)\) 时符合要求。

代码

#include <bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;

const int N = 2510;
const int M = 1e5 + 10;
const int INF = 1e9;

struct flow {
    int cnt = 1, hd[N], nxt[M * 2], to[M * 2], limit[M * 2];
    void add(int u, int v, int w) {
        nxt[++cnt] = hd[u], hd[u] = cnt, to[cnt] = v, limit[cnt] = w;
        nxt[++cnt] = hd[v], hd[v] = cnt, to[cnt] = u, limit[cnt] = 0;
    }
    int T, dis[N], cur[N];
    i64 dfs(int id, i64 res) {
        if(id == T) return res;
        i64 flow = 0;
        for(int i = cur[id]; i && res; i = nxt[i]) {
            cur[id] = i;
            int c = std::min(res, (i64)limit[i]), it = to[i];
            if(dis[id] + 1 == dis[it] && c) {
                int k = dfs(it, c);
                flow += k, res -= k, limit[i] -= k, limit[i ^ 1] += k;
            }
        }
        if(!flow) dis[id] = -1;
        return flow;
    }
    i64 maxflow(int s, int t) {
        T = t;
        i64 flow = 0;
        while(1) {
            std::queue<int> q;
            memcpy(cur, hd, sizeof(hd));
            memset(dis, 0xff, sizeof(dis));
            q.push(s), dis[s] = 0;
            while(q.size()) {
                int u = q.front();
                q.pop();
                for(int i = hd[u]; i; i = nxt[i]) {
                    if(dis[to[i]] == -1 && limit[i]) {
                        dis[to[i]] = dis[u] + 1;
                        q.push(to[i]);
                    }
                }
            }
            if(dis[t] == -1) return flow;
            flow += dfs(s, 1e18);
        }
    }
};

std::string a[55];

void solve(void) {
    int n, a1, a2, an, b1, b2, bn;
    flow g;
    while(std::cin >> n >> a1 >> a2 >> an >> b1 >> b2 >> bn) {
        for(int i = 1; i <= n; i++) {
            std::cin >> a[i];
            a[i] = " " + a[i];
        }
        a1++, a2++, b1++, b2++;
        g.cnt = 1;
        memset(g.hd, 0, sizeof(g.hd));
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(a[i][j] == 'O') {
                    g.add(i, j, 2);
                }
                if(a[i][j] == 'N') g.add(i, j, INF);
            }
        }
        flow g1 = g, g2 = g;
        int S = n + 1, T = n + 2;
        g1.add(S, a1, 2 * an);
        g1.add(S, b1, 2 * bn);
        g1.add(a2, T, 2 * an);
        g1.add(b2, T, 2 * bn);
        int cnt1 = g1.maxflow(S, T);
        g2.add(S, a1, 2 * an);
        g2.add(S, b2, 2 * bn);
        g2.add(a2, T, 2 * an);
        g2.add(b1, T, 2 * bn);
        int cnt2 = g2.maxflow(S, T);
        //std::cout << cnt1 << " " << cnt2 << '\n';
        if(cnt1 == 2 * (an + bn) && cnt2 == 2 * (an + bn)) {
            std::cout << "Yes\n";
        } else std::cout << "No\n";
    }
}

int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t = 1;
    //std::cin >> t;
    while(t--) solve();
    return 0;
}

P4281 [AHOI2008] 紧急集合 / 聚会

思路

对三个点,先两两的求一下 LCA ,可以发现三个 LCA 只有两种情况:完全相同或者分两个在左右子树上。对于相同的情况,直接计算就好了。对于不相同的情况,显然让单个的点先从远端的 LCA 走到近端的 LCA 比两个点从近端的 LCA 走到远端更划算。

算一下距离:

\[dep_a - dep_{low} + dep_b - dep_{low} + dep_c - dep_{high} + dep_{low} - dep_{high} \]

化简一下就成了:

\[dep_a + dep_b + dep_c - 2 \times dep_{high} - dep_{low} \]

代码

#include <bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;

const int N = 2510;
const int M = 1e5 + 10;
const int INF = 1e9;


//0-base
struct LCA {
    int n, LOG;
    std::vector<int> dep;
    std::vector<std::vector<int>> up;
    std::vector<std::vector<int>> adj;
    LCA(int n_) : n(n_) {
        LOG = 0;
        while ((1 << LOG) <= n) LOG++;
        dep.assign(n, 0);
        up.assign(LOG, std::vector<int>(n, -1));
        adj.assign(n, std::vector<int>());
    }
    void add(int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    void dfs(int v, int p) {
        up[0][v] = p;
        for (int i = 1; i < LOG; i++) {
            if (up[i - 1][v] != -1) {
                up[i][v] = up[i - 1][up[i - 1][v]];
            } else {
                up[i][v] = -1;
            }
        }
        for (auto to : adj[v]) {
            if (to == p) continue;
            dep[to] = dep[v] + 1;
            dfs(to, v);
        }
    }
    //加完边再初始化
    void init(int root = 0) {
        dfs(root, -1);
    }
    int query(int u, int v) {
        if (dep[u] < dep[v]) std::swap(u, v);
        int diff = dep[u] - dep[v];
        for (int i = 0; i < LOG; i++) {
            if (diff & (1 << i)) {
                u = up[i][u];
                if (u == -1) break;
            }
        }
        if (u == v) return u;
        for (int i = LOG - 1; i >= 0; i--) {
            if (up[i][u] != up[i][v]) {
                u = up[i][u];
                v = up[i][v];
            }
        }
        return up[0][u];
    }
};

void solve(void) {
    int n, m; std::cin >> n >> m;
    LCA lca(n + 1);
    for(int i = 1; i < n; i++) {
        int u, v; std::cin >> u >> v;
        lca.add(u, v);
    }
    lca.init(1);
    while(m--) {
        int x, y, z; std::cin >> x >> y >> z;
        int a = lca.query(x, y);
        int b = lca.query(y, z);
        int c = lca.query(x, z);
        int high = a != b ? (lca.dep[a] < lca.dep[b] ? a : b) : a;
        int low = a != b ? (lca.dep[a] > lca.dep[b] ? a : b) : c;
        std::cout << low << " " << lca.dep[x] + lca.dep[y] + lca.dep[z] - 2 * lca.dep[high] - lca.dep[low] << '\n';
    }
}

int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t = 1;
    //std::cin >> t;
    while(t--) solve();
    return 0;
}

P1967 [NOIP 2013 提高组] 货车运输

思路

显然,货车是不会走回路的,因为这样没有意义。因此对于任何一辆车来说,最好情况下他能运输的货物数量就是最大生成树中,两点之间路径中的最小边。因此可以先找出最大生成树(可能是森林),然后使用倍增的方法查找两点间的最小边。

如果两点不在一棵生成树中,那么无解。

代码

#include <bits/stdc++.h>

#define x first
#define y second

using i64 = long long;
using u64 = unsigned long long;

using PII = std::pair<int, int>;

const int N = 2510;
const int M = 1e5 + 10;
const int INF = 1e9;

//0-base
//维护树上路径中的最小边
struct LCA {
    int n, LOG;
    std::vector<int> dep;
    std::vector<std::vector<int>> up;
    std::vector<std::vector<int>> minw;
    std::vector<std::vector<PII>> adj;
    LCA(int n_) : n(n_) {
        LOG = 0;
        while ((1 << LOG) <= n) LOG++;
        dep.assign(n, 0);
        up.assign(LOG, std::vector<int>(n, -1));
        adj.assign(n, std::vector<PII>());
        minw.assign(LOG, std::vector<int>(n, INF));
    }
    void add(int u, int v, int w) {
        adj[u].emplace_back(v, w);
        adj[v].emplace_back(u, w);
    }
    void dfs(int v, int p, int w) {
        up[0][v] = p;
        minw[0][v] = (p == -1 ? INF : w);
        for (int i = 1; i < LOG; i++) {
            if (up[i - 1][v] != -1) {
                up[i][v] = up[i - 1][up[i - 1][v]];
                minw[i][v] = std::min(minw[i - 1][v], minw[i - 1][up[i - 1][v]]);
            } else {
                up[i][v] = -1;
                minw[i][v] = INF;
            }
        }
        for (auto [to, w] : adj[v]) {
            if (to == p) continue;
            dep[to] = dep[v] + 1;
            dfs(to, v, w);
        }
    }
    //加完边再初始化
    void init(int root = 0) {
        for(int i = 1; i <= n; i++) {
            if(up[0][i] == -1) {
                dep[i] = 0;
                dfs(i, -1, INF);
            }
        }
    }
    //返回路径上的最小边权
    int query(int u, int v) {
        if (dep[u] < dep[v]) std::swap(u, v);
        int res = INF;
        int diff = dep[u] - dep[v];
        for (int i = 0; i < LOG; i++) {
            if (diff & (1 << i)) {
                res = std::min(res, minw[i][u]);
                u = up[i][u];
                if (u == -1) break;
            }
        }
        if (u == v) return res;
        for (int i = LOG - 1; i >= 0; i--) {
            if (up[i][u] != up[i][v]) {
                res = std::min(res, minw[i][u]);
                res = std::min(res, minw[i][v]);
                u = up[i][u];
                v = up[i][v];
            }
        }
        res = std::min(res, minw[0][u]);
        res = std::min(res, minw[0][v]);
        return res;
    }
};

struct DSU {
    std::vector<int> p, siz;
    DSU(int n): p(n + 1), siz(n + 1, 1) {
        std::iota(p.begin(), p.end(), 0);
    }
    int find(int x) {
        if(x == p[x]) return p[x];
        return p[x] = find(p[x]);
    }
    bool unite(int a, int b) {
        int pa = find(a), pb = find(b);
        if(pa == pb) return false;
        if(siz[pa] < siz[pb]) std::swap(pa, pb);
        p[pb] = pa;
        siz[pa] += siz[pb];
        return true;
    }
    bool same(int u, int v) {return find(u) == find(v);}
    int size(int u) {return siz[find(u)];}
};

struct Edge {
    int u, v, w;
};
void solve(void) {
    int n, m; std::cin >> n >> m;
    std::vector<Edge> e(m + 1);
    for(int i = 1; i <= m; i++) {
        std::cin >> e[i].u >> e[i].v >> e[i].w;
    }
    std::sort(e.begin() + 1, e.end(), [](Edge x, Edge y) {
        return x.w > y.w;
    });
    DSU dsu(n);
    LCA lca(n + 1);
    for(int i = 1; i <= m; i++) {
        if(dsu.unite(e[i].u, e[i].v)) {
            lca.add(e[i].u, e[i].v, e[i].w);
        }
    }
    lca.init();
    int q; std::cin >> q;
    for(int i = 1; i <= q; i++) {
        int x, y; std::cin >> x >> y;
        if(!dsu.same(x, y)) {
            std::cout << "-1\n";
        }
        else std::cout << lca.query(x, y) << '\n';
    }
}

int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t = 1;
    //std::cin >> t;
    while(t--) solve();
    return 0;
}

P5057 [CQOI2006] 简单题

思路

简单的线段树题,要求对01区间实现两个操作:
1.区间内的每个数字异或上 \(1\) ;
2.查询某一位置上的数字。

简单修改一下之前的模版,对于修改操作,直接讲 tag 改成 \(tag[o] \oplus = 1\)

对于查询操作,由于,由于模版本身的单点和区间查询都来源于区间查询,所以维护 \(sum\) 数组,每次修改后, \(sum[o] = (r - l + 1) - sum[o]\)

代码

#include<bits/stdc++.h>
#define x first
#define y second
using i64 = long long;
using u64 = unsigned long long;
using u128 = __uint128_t;
using PII = std::pair<int, int>;
const int N = 10000;
const int M = 30000;
const i64 INF = 1e18;
const double eps = 1e-6;
//本模板下标默认从1开始
struct SegTree {
    int n;
    std::vector<int> sum, tag;
    SegTree(int n_): n(n_) {
        sum.assign(4 * n, 0);
        tag.assign(4 * n, -1);
    }
    void pull(int o) {
        sum[o] = sum[o * 2] + sum[o * 2 + 1];
    }
    void apply(int o, int l, int r) {
        sum[o] = (r - l + 1) - sum[o];
        tag[o] ^= 1;
    }
    void push(int o, int l, int r) {
        if(tag[o] != -1) {
            int m = (l + r) / 2;
            apply(o * 2, l, m); 
            apply(o * 2 + 1, m + 1, r);
            tag[o] = -1;
        }
    }
    void build(int o, int l, int r, const std::vector<int> &a) {
        tag[o] = -1;
        if(l == r) {
            sum[o] = a[l];
            return;
        }
        int m = (l + r) / 2;
        build(o * 2, l, m, a);
        build(o * 2 + 1, m + 1, r, a);
        pull(o);
    }
    void build(const std::vector<int> &a) {
        build(1, 1, n, a);
    }
    int query(int o, int l, int r, int L, int R) {
        if(R < l || r < L) return 0;
        if(L <= l && r <= R) return sum[o];
        push(o, l, r);
        int m = (l + r) / 2;
        return query(o * 2, l, m, L, R) + query(o * 2 + 1, m + 1, r, L, R);
    }
    int query_sum(int x, int y) {
        return query(1, 1, n, x, y);
    }
    void update(int o, int l, int r, int L, int R) {
        if(R < l || r < L) return;
        if(L <= l && r <= R) {
            apply(o, l, r);
            return;
        }
        push(o, l , r);
        int m = (l + r) / 2;
        update(o * 2, l, m, L, R);
        update(o * 2 + 1, m + 1, r, L, R);
        pull(o);
    }
    void update(int x, int y) {
        update(1, 1, n, x, y);
    }
    int query(int o, int l, int r, int p) {
        if(l == r) return sum[o];
        push(o, l, r);
        int m = (l + r) / 2;
        if(p <= m) return query(o * 2, l, m, p);
        return query(o * 2 + 1, m + 1, r, p);
    }
    int query_point(int p) {
        return query(1, 1, n, p);
    }
};
void solve(void) {
    int n, m; std::cin >> n >> m;
    std::vector<int> a(n + 1, 0);
    SegTree seg(n + 1);
    seg.build(a);
    while(m--) {
        int op; std::cin >> op;
        if(op == 1) {
            int l, r; std::cin >> l >> r;
            seg.update(l, r);
        } else {
            int i; std::cin >> i;
            std::cout << seg.query_point(i) << '\n';
        }
    }
}
int main(void) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t = 1;
    //std::cin >> t;
    while(t--) solve();
    return 0;
}

P2846 [USACO08NOV] Light Switching G

思路

经验++

一摸一样的题目,单点查询改成了区间查询总和。代码就不放了。

P2574 XOR的艺术

思路

经验++

还是一摸一样的题目,把全零的数组改成01串。

posted @ 2025-09-01 02:21  dbywsc  阅读(8)  评论(0)    收藏  举报