2025-11-16~17 hetao1733837的刷题记录

2025-11-16~17 hetao1733837的刷题记录

11.16

[JSOI2008] 星球大战

原题链接:[JSOI2008] 星球大战

分析

很显然,对于一些多次修改的图论题 离线下来倒着做 \color{Black}{离线下来倒着做} 离线下来倒着做,有时候是很优的,特别是删边!

那么,顺理成章开始HE题解......

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 400005;
int n, m, ans[N], k, p[N];
bool vis[N];
int fa[N];
int head[N];
struct node{
    int nxt, frm, to;
}e[N];
int tot;
void add(int u, int v){
    e[++tot].frm = u;
    e[tot].nxt = head[u];
    head[u] = tot;
    e[tot].to = v;
}
int find(int x){
    return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
}
void merge(int x, int y){
    int fx = find(x), fy = find(y);
    if (fx != fy){
        fa[fy] = fx;
    }
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    memset(head, -1, sizeof(head));
    for (int i = 0; i < n; i++){
        fa[i] = i;
    }
    for (int i = 1; i <= m; i++){
        int x, y;
        cin >> x >> y;
        add(x, y);
        add(y, x);
    }
    cin >> k;
    for (int i = 1; i <= k; i++){
        cin >> p[i];
        vis[p[i]] = 1;
    }
    int cnt = n - k;
    for (int i = 1; i <= tot; i++){
        if (!vis[e[i].frm] && !vis[e[i].to] && find(e[i].frm) != find(e[i].to)){
            cnt--;
            merge(e[i].frm, e[i].to);
        }
    }
    ans[k + 1] = cnt;
    for (int i = k; i >= 1; i--){
        cnt++;
        vis[p[i]] = 0;
        for (int v = head[p[i]]; v != -1; v = e[v].nxt){
            if (!vis[e[v].to] && find(p[i]) != find(e[v].to)){
                cnt--;
                merge(p[i], e[v].to);
            }
        }
        ans[i] = cnt;
    }
    for (int i = 1; i <= k + 1; i++)
        cout << ans[i] << '\n';
    return 0;
}

「Wdsr-2.7」文文的摄影布置

原题链接:「Wdsr-2.7」文文的摄影布置

分析

19点49分

线段树?我印象中写过这题,但是没找到提交记录。那么问题就在于第三种操作,区间最小值也好差,但是, i i i和 k k k如何确定?容我稍考......显然 O ( n 2 ) O(n^2) O(n2)不可能放你,要不然不可能评蓝。

情绪有点低落啊......时间不晚......

20点09分

开始看题解。哦?问题转化为求:

max ⁡ l ≤ a < b ≤ r A a − B b \max\limits_{l\le a<b\le r}{A_a-B_b} l≤a<b≤rmaxAa−Bb

max ⁡ l ≤ b < c ≤ r A c − B b \max\limits_{l\le b<c\le r}{A_c-B_b} l≤b<c≤rmaxAc−Bb

那么,可以写代码了?

正解

操,写了一个小时!虽然水群了......

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 500005;
const int INF = 0x3f3f3f3f;
const int NEG_INF = 0xc0c0c0c0;
struct node{
    int a, b, p, q, w;
    node() : a(NEG_INF), b(INF), p(NEG_INF), q(NEG_INF), w(NEG_INF){}
    node(int a_val, int b_val) : a(a_val), b(b_val), p(NEG_INF), q(NEG_INF), w(NEG_INF){}
    node operator + (const node& tmp) const {
        node k;
        k.a = max(a, tmp.a);
        k.b = min(b, tmp.b);
        k.p = max({tmp.p, p, a - tmp.b});
        k.q = max({tmp.q, q, tmp.a - b});
        k.w = max({w, tmp.w, p + tmp.a, tmp.q + a});
        return k;
    }
};
int n, m;
int A[N], B[N];
struct segtree{
    node tr[N << 2];
    void pushup(int p, int l, int r, int s){
        if (l == r){
            tr[p] = node(A[l], B[l]);
            return ;
        }
        int mid = (l + r) >> 1;
        if (s <= mid)
            pushup(p << 1, l, mid, s);
        else
            pushup(p << 1 | 1, mid + 1, r, s);
        tr[p] = tr[p << 1] + tr[p << 1 | 1];
    }
    void build(int p, int l, int r){
        if (l == r){
            tr[p] = node(A[l], B[l]);
            return ;
        }
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        tr[p] = tr[p << 1] + tr[p << 1 | 1];
    }
    node query(int p, int l, int r, int s, int t){
        if (s <= l && r <= t){
            return tr[p];
        }
        int mid = (l + r) >> 1;
        if (t <= mid)
            return query(p << 1, l, mid, s, t);
        if (s > mid)
            return query(p << 1 | 1, mid + 1, r, s, t);
        return query(p << 1, l, mid, s, t) + query(p << 1 | 1, mid + 1, r, s, t);
    }
}T;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> A[i];
    for (int i = 1; i <= n; i++)
        cin >> B[i];
    T.build(1, 1, n);
    int op, l, r;
    while (m--){
        cin >> op >> l >> r;
        if (op == 1){
            A[l] = r;
            T.pushup(1, 1, n, l);
        }
        else if (op == 2){
            B[l] = r;
            T.pushup(1, 1, n, l);
        }
        else if (op == 3){
            node result = T.query(1, 1, n, l, r);
            cout << result.w << '\n';
        }
    }
    return 0;
}

楼房重建

原题链接:楼房重建

分析

能看到楼房,简单来说就是前面没有比它高的。难道是单调栈?复杂度让你飞起来,考虑线段树......居然还有分块!但我不会......

21点20分

线段树怎么维护呢?我稍考一下......

难道是区间最值等于本身?有点阴了,时间复杂度也不能接受吧......大概是 O ( m n l o g n ) O(mnlogn) O(mnlogn)?

21点24分

开看题解......喔,居然是顶点连线求凸包状物?有点nb了。哦,线段树维护区间最值及区间(从区间左端点开始,大于前一项必选,小于等于必不选的子序列长度)。合并时,左儿子一定全选,对于右儿子,最大值小于左儿子没有贡献,反之,找到大于左儿子最大值的位置继续递归处理。

我会写代码吗?

难点在于 p u s h u p 2 pushup2 pushup2。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n, m;
int x, y;
double a[N];
struct segtree{
	double mx[N << 2];
    int len[N << 2];
	void pushup1(int p){
		mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
	}
	int pushup2(int p, int l, int r, double maxn){
		if (mx[p] <= maxn)
			return 0;
		if (a[l] > maxn)
			return len[p];
		if (l == r)
			if (a[l] > maxn)
				return 1;
			else
				return 0;
		int ls = p << 1, rs = p << 1 | 1;
		int mid = (l + r) >> 1;
		if (mx[ls] <= maxn)
			return pushup2(rs, mid + 1, r, maxn);
		else
			return pushup2(ls, l, mid, maxn) + len[p] - len[ls]; 
	}
	void modify(int p, int l, int r, int s, int v){
		if (l == r && l == s){
			mx[p] = (double)v / s;
			len[p] = 1;
			return ;
		}
		int mid = (l + r) >> 1;
		if (s <= mid)
			modify(p << 1, l, mid, s, v);
		if (s > mid)
			modify(p << 1 | 1, mid + 1, r, s, v);
		pushup1(p);
		len[p] = len[p << 1] + pushup2(p << 1 | 1, mid + 1, r, mx[p << 1]);
	}
}T;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++){
		cin >> x >> y;
		a[x] = (double) y / x;
		T.modify(1, 1, n, x, y);
		cout << T.len[1] << '\n';
	}
}

我是**,mx开成int了,居然还过了50分,数据有点水。

11.17

[JSOI2008] 最大数

原题链接:[JSOI2008] 最大数

分析

线段树动态开点因该可以吧......

11点42分

操了,电脑死机了。开he题解。

Oh,以前写过,不用动开,直接建空树,modify和query即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int M, a[N], D;
long long L, n;
char c;
struct Sgement_Tree{
    #define mid (l + r >> 1)
    int mx[N << 2];
    void pushup(int p){
        mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
    }
    void build(int p, int l, int r){
        if (l == r){
            mx[p] = a[l];
            return ;
        }
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        pushup(p);
    }
    int query(int p, int l, int r, int s, int t){
        if (l >= s && r <= t)
            return mx[p];
        int ans = 0xc0c0c0c0;
        if (s <= mid)
            ans = query(p << 1, l, mid, s, t);
        if (t > mid)
            ans = max(ans, query(p << 1 | 1, mid + 1, r, s, t));
        return ans;
    }
    void modify(int p, int l, int r, int s, int t){
        if (l == r){
            mx[p] += t;
            return ;
        }
        if (s <= mid)
            modify(p << 1, l, mid, s, t);
        else
            modify(p << 1 | 1, mid + 1, r, s, t);
        pushup(p);
    }
}T;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> M >> D;
    long long lst = 0;
    int tot = 0;
    T.build(1, 1, M);
    for (int i = 1; i <= M; i++){
        cin >> c;
        if (c == 'Q'){
            cin >> L;
            lst = T.query(1, 1, M, tot - L + 1, tot);
            cout << lst << '\n';
        }
        else if (c == 'A'){
            cin >> n;
            ++tot;
            T.modify(1, 1, M, tot, (lst + n) % D);
        }
    }
}

I Hate It

原题链接:P1531 I Hate It

分析

什么?绿题一发过!虽然是板子吧......OK,线段树,还行。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, m, a[N];
struct segtree{
    int mx[N << 2];
    void pushup(int p){
        mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
    }
    void build(int p, int l, int r){
        if (l == r){
            mx[p] = a[l];
            return ;
        }
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        pushup(p);
    }
    int query(int p, int l, int r, int s, int t){
        if (l >= s && r <= t){
            return mx[p];
        }
        int ans = 0xc0c0c0c0;
        int mid = (l + r) >> 1;
        if (s <= mid)
            ans = max(ans, query(p << 1, l, mid, s, t));
        if (t > mid)
            ans = max(ans, query(p << 1 | 1, mid + 1, r, s, t));
        return ans;
    }
    void modify(int p, int l, int r, int s, int v){
        if (l == r){
            mx[p] = max(mx[p], v);
            return ;        
        }
        int mid = (l + r) >> 1;
        if (s <= mid)
            modify(p << 1, l, mid, s, v);
        else
            modify(p << 1 | 1, mid + 1, r, s, v);
        pushup(p);
    }
}T;
int main(){
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    T.build(1, 1, n);
    while (m--){
        int a, b;
        char c;
        cin >> c >> a >> b;
        if (c == 'Q'){
            cout << T.query(1, 1, n, a, b) << '\n'; 
        }
        if (c == 'U'){
            T.modify(1, 1, n, a, b);
        }
    }
}

[JOISC 2014] JOIOJI

原题链接:[JOISC 2014] JOIOJI

分析

我是**,本题没有直接秒掉是因为对于 m a p map map不熟练,要在练习中多加打磨。

正解

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
map<pair<int, int>, int> mp;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> s;
    s = " " + s;
    mp[{0, 0}] = 0;
    int maxn = 0;
    int J = 0, O = 0, I = 0;
    for (int i = 1; i <= n; i++){
        if (s[i] == 'J') 
            J++;
        if (s[i] == 'O') 
            O++;
        if (s[i] == 'I') 
            I++;
        int tmp1 = J - O, tmp2 = O - I;
        if (mp.find({tmp1, tmp2}) != mp.end()){
            maxn = max(maxn, i - mp[{tmp1, tmp2}]);
        }
        else{
            mp[{tmp1, tmp2}] = i;
        }
    }
    cout << maxn;
}

[JOISC 2014] 电压 / Voltage

原题链接:[JOISC 2014] 电压 / Voltage

分析

是个图......啊?割边?还有个电阻的限制......限制一下奇偶性......

二分图???

20点55分

开始看题解,哦?图上奇偶性转化为 奇环、偶环 \color{Black}{奇环、偶环} 奇环、偶环。

那么,如果图中存在奇环,选的是所有奇环上边的交集且不得在偶环上。不存在奇环,随便选。

好吧,我并不理解,但代码可以he!

正解

忘了读入 n , m n,m n,m,我是**

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005, M = 200005;
struct node{
	int nxt, v;
}e[M << 1];
int head[N];
int cnt = 1;
void add(int u, int v){
	e[++cnt].nxt = head[u];
	e[cnt].v = v;
	head[u] = cnt;
}
int n, m;
bool vis[N], rt[N];
int de[N], sum[N][2], tot;
int f[N];
void dfs(int u){
	vis[u] = 1;
	for (int i = head[u]; i; i = e[i].nxt){
		int v = e[i].v;
		if (i == f[u] || (i ^ 1) == f[u])
			continue;
		if (vis[v]){
			if (de[v] > de[u])
				continue;
			int d = (de[u] - de[v]) & 1;
			sum[u][d]++;
			sum[v][d]--;
			if (!d)
				tot++;
		}
		else{
			f[v] = i;
			de[v] = de[u] + 1;
			dfs(v);
			sum[u][0] += sum[v][0];
			sum[u][1] += sum[v][1]; 
		}	
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++){
		int u, v;
		cin >> u >> v;
		add(u, v);
		add(v, u);
	}
	for (int i = 1; i <= n; i++){
		if (!vis[i]){
			rt[i] = 1;
			dfs(i);
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; i++){
		if (sum[i][0] == tot && !sum[i][1] && !rt[i])
			ans++;
	}
	if (tot == 1)
		ans++;
	cout << ans;
}

[JOISC 2014] 挂饰 / Straps

原题链接:[JOISC 2014] 挂饰 / Straps

分析

很像背包,但是我不会???

操,我会了,设 d p i , j dp_{i,j} dpi,j表示前 i i i个物品, j j j个挂钩的最大收益。

那么,转移很容易,

d p i , j = max ⁡ ( d p i , j , d p i − 1 , j − a i + b i ) dp_{i,j}=\max(dp_{i,j},dp_{i-1,j-a_i}+b_i) dpi,j=max(dpi,j,dpi−1,j−ai+bi)

还是很🐂🍺,转移方程一遍过,不过题解对 j − a i j-a_i j−ai和 0 0 0取了 max ⁡ \max max,不太理解,觉得没啥必要。

正解

转移方程原理差不多,增加了一些。

cp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
const int INF = 0x3f3f3f3f;
struct node {
    int a, b;
} inp[N];
int n;
int f[N][N];
bool cmp(node x, node y){
    return x.a > y.a; 
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> inp[i].a >> inp[i].b;
    }
    sort(inp + 1, inp + n + 1, cmp);
    for (int i = 0; i <= n; i++){
        for (int j = 0; j <= n + 1; j++){
            f[i][j] = -INF;
        }
    }
    f[0][1] = 0;
    for (int i = 1; i <= n; i++){
        for (int j = 0; j <= n; j++){
            f[i][j] = max(f[i][j], f[i - 1][j]);
            if (j >= 1 && f[i - 1][j] != -INF){
                int v = j - 1 + inp[i].a; 
                v = min(v, n); 
                f[i][v] = max(f[i][v], f[i - 1][j] + inp[i].b);
            }
        }
    }
    int ans = 0;
    for (int j = 0; j <= n; j++){
        ans = max(ans, f[n][j]);
    }
    cout << ans << endl;
    return 0;
}
相关推荐
_OP_CHEN2 小时前
算法基础篇:(九)贪心算法拓展之推公式:从排序规则到最优解的推导艺术
c++·算法·贪心算法·推公式·算法竞赛·acm/icpc
czxyvX2 小时前
010-C++之List
开发语言·c++·list
小艳加油2 小时前
生态学研究突破:利用R语言多元算法实现物种气候生态位动态分析与分布预测,涵盖数据清洗、模型评价到论文写作全流程
开发语言·算法·r语言
t198751283 小时前
基于盲源分离与贝叶斯非局部均值(BM3D)的图像降噪算法实现
算法·计算机视觉·均值算法
2501_941111843 小时前
分布式日志系统实现
开发语言·c++·算法
AA陈超3 小时前
UE5笔记:OnComponentBeginOverlap
c++·笔记·学习·ue5·虚幻引擎
不会c嘎嘎3 小时前
C++ -- stack和queue
开发语言·c++·rpc
CodeByV3 小时前
【C++】C++11:其他重要特性
开发语言·c++
2501_941111334 小时前
C++代码重构实战
开发语言·c++·算法