2025-12-02~03 hetao1733837的刷题记录

2025-12-02~03 hetao1733837的刷题记录

12-02

LG2391 白雪皑皑

原题链接:白雪皑皑

分析

呃,一眼线段树,但是我好像不会,就是说是区间赋值没毛病,真的直接赋值吗?那很好了。

oh,难点在于多次修改,而且修改次数是 1 × 1 0 7 1\times 10^7 1×107 级别的, l o g log log 根本跑步下。那么就要预处理出类似于线段覆盖的东西,那岂不是思维题然后 不用数据结构了?这么神秘?难道是同余方程求解?这么牛?那不就成🍬题了?

我是🍬......

区间多次覆盖,想到了并查集,然后用并查集维护,倒序枚举最后一次覆盖是什么颜色,做完了。

我还是觉得解同余方程有前途。

同时,我看的那篇题解给出了另一道题,有空了再写,要是哪位看到博客,可以在评论区提醒我回来写!/bx

设 f a i fa_i fai 表示 i i i 位置后面第一个没有被染色的,中间统一染成一个颜色,没了。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1000005;
int n, m, p, q;
int col[N], fa[N];
int find(int x){
	return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
}
void merge(int x, int y){
	fa[x] = y;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> p >> q;
	for (int i = 1; i <= n; i++){
		fa[i] = i;
	}
	for (int i = m; i >= 1; i--){
		int l = (i * p + q) % n + 1;
		int r = (i * q + p) % n + 1;
		if (l > r){
			swap(l, r);
		}
		for (int j = r; j >= l; ){
			int faj = find(j);
			if (faj == j){
				col[j] = i;
				merge(j, find(j - 1));
			}
			j = fa[j];
		}
	}
	for (int i = 1; i <= n; i++)
		cout << col[i] << '\n';
}

然后就是学点新东西吧,线段树上二分,线段树分治,线段树分裂,线段树合并,李超线段树......🤮

可持久化也是必备技能吧。

12-03

LG13979 数列分块入门 4

原题链接:数列分块入门 4

分析

呃······我不清楚是不是会了。思想很顺理成章,我也知道代码为啥这么写,但是还是不会自己写。

我理解错了,块的个数不等于块的长度! 然后样例里长度为2,个数也为2,炸了。

还有,别忘了 懒标记下放!

何意味,调不出来/(ㄒoㄒ)/~~

正解

何意味,我代码不是和正解一样吗?改个变量名就WA?哦,真的要开到500吗?

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 300005, M = 555;
int a[N], tag[M], sum[M];
int n, op, l, r, c;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	int len = sqrt(n);
	for (int i = 1; i <= n; i++){
		cin >> a[i];
		sum[(i - 1) / len + 1] = sum[(i - 1) / len + 1] + a[i];
	}
    int t = n;
    while (t--){
		cin >> op >> l >> r >> c;
		int nl = (l - 1) / len + 1, nr = (r - 1) / len + 1;
		if (op == 0){
			if (nl == nr){ 
				for (int i = l; i <= r; i++){
					a[i] += c;
					sum[nl] = sum[nl] + c;
				}
			} 
            else{
				for (int i = l; i <= nl * len; i++){ 
    				a[i] += c;
					sum[nl] = sum[nl] + c;
				}
				for (int i = nl + 1; i < nr; i++){
					tag[i] += c;
					sum[i] += len * c;
				}
				for (int i = (nr - 1) * len + 1; i <= r; i++){ 
					a[i] += c;
					sum[nr] += c;
				}
			}
		}
        if (op == 1){
			c++; 
			int ans = 0;
			if(nl == nr){
				for (int i = l; i <= r; i++){
					ans += a[i] + tag[nl];
				}
			}
            else{
				for (int i = l; i <= nl * len; i++){ 
					ans += a[i] + tag[nl]; 
				}
				for (int i = nl + 1; i < nr; i++){ 
					ans += sum[i];
				}
				for (int i = (nr - 1) * len + 1; i <= r; i++){ 
					ans += a[i] + tag[nr];
				}
			}
			cout << (ans % c + c) % c << "\n";
		}
	}
}

LG2357 守墓人

原题链接:守墓人

分析

刷题解看到了这篇,感觉题目名很浪漫,决定写一写。

看了难度,应该是树状数组板子吧......没过/(ㄒoㄒ)/~~

呃,开两个,分别记录单点修改的值和区间和,没了,整体担心复杂度可以单开一个 t a g tag tag,优化挺大的。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200005;
int n, f, a[N], c1[N], c2[N];
int op, l, r, k;
int tag;
void add(int x, int v){
	for (int i = x; i <= n; i += i & (-i)){
		c1[i] += v;
		c2[i] += x * v;
	}
}
int query(int x){
	int ans = 0;
	for (int i = x; i; i -= i & (-i)){
		ans += (x + 1) * c1[i] - c2[i];
	}
	return ans;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> f;
	for (int i = 1; i <= n; i++){
		cin >> a[i];
		add(i, a[i] - a[i - 1]);	
	}
	for (int cs = 1; cs <= f; cs++){
		cin >> op;
		if (op == 1){
			cin >> l >> r >> k;
			add(l, k);
			add(r + 1, -k);
		}
		if (op == 2){
			cin >> k;
			tag += k;
		}
		if (op == 3){
			cin >> k;
			tag -= k;
		}
		if (op == 4){
			cin >> l >> r;
			int ans = query(r) - query(l - 1);
			if (l == 1)
				ans += tag; 
			cout << ans << '\n';
		}
		if (op == 5){
			cout << query(1) + tag << '\n';
		}
	}
}

LG10463 Interval GCD

原题链接:Interval GCD

分析

区间 gcd ⁡ \gcd gcd 能线段树吗?我咋不太信啊......显然,我们见多识广,在核桃国庆的时候,出现了用 ST 表统计区间 gcd ⁡ \gcd gcd 的操作,lrh 告诉我,ST 表能干的事,线段树也能干!可合并就是可用线段树维护,懂了!

何意味?我居然不会down!呃,似乎不变(辗转相减发得出)。

我是**,有一个性质: gcd ⁡ ( a 1 , a 2 , . . . , a n ) = gcd ⁡ ( a 1 , a 1 − a 2 , a 3 − a 2 , . . . , a n − a n − 1 ) \gcd(a_1, a_2,...,a_n)=\gcd(a_1, a_1-a_2,a_3-a_2,...,a_n-a_{n-1}) gcd(a1,a2,...,an)=gcd(a1,a1−a2,a3−a2,...,an−an−1)

那就多个差分数组的事了!

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500005;
int n, m, a[N];
char op;
int l, r, d;
struct segtree{
    int sum[N << 2], gcd[N << 2];
    void pushup(int p) {
        sum[p] = sum[p << 1] + sum[p << 1 | 1];
        gcd[p] = __gcd(gcd[p << 1], gcd[p << 1 | 1]);
    }
    void build(int p, int l, int r){
        if (l == r) {
            sum[p] = gcd[p] = a[l] - a[l - 1]; 
            return ;
        }
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        pushup(p);
    }
    void modify(int p, int l, int r, int pos, int v){ 
        if (l == r) {
            sum[p] += v;
            gcd[p] += v;
            return ;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid)
            modify(p << 1, l, mid, pos, v);
        else
            modify(p << 1 | 1, mid + 1, r, pos, v);
        pushup(p);
    }
    int query_sum(int p, int l, int r, int s, int t){ 
        if (s <= l && r <= t){
            return sum[p];
        }
        int mid = (l + r) >> 1;
        int ans = 0;
        if (s <= mid)
            ans += query_sum(p << 1, l, mid, s, t);
        if (t > mid)
            ans += query_sum(p << 1 | 1, mid + 1, r, s, t);
        return ans;
    }
    int query_gcd(int p, int l, int r, int s, int t){
        if (s <= l && r <= t){
            return gcd[p];
        }
        int mid = (l + r) >> 1;
        int ans = 0;
        if (s <= mid)
            ans = __gcd(ans, query_gcd(p << 1, l, mid, s, t));
        if (t > mid)
            ans = __gcd(ans, query_gcd(p << 1 | 1, mid + 1, r, s, t));
        return ans;
    }
} T;
signed 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];
    }
    T.build(1, 1, n);
    for (int cs = 1; cs <= m; cs++) { 
        cin >> op >> l >> r;
        if (op == 'C'){
            cin >> d;
            T.modify(1, 1, n, l, d);
            if (r + 1 <= n)
                T.modify(1, 1, n, r + 1, -d);
        }
        if (op == 'Q'){
            int g = T.query_sum(1, 1, n, 1, l);
            if (l + 1 <= r)
                g = __gcd(g, T.query_gcd(1, 1, n, l + 1, r));
            cout << abs(g) << '\n';
        }
    }
    return 0;
}

LG3293 [SCOI2016] 美味

原题链接:[SCOI2016] 美味

分析

所以,紫题终究还是切不了吗/(ㄒoㄒ)/~~

我认为应该开3个懒标记,分别记录区间异或值,区间和,还有......咋忘了?呃,按位取反吗?更恐怖了。

这就是初步思路,然后,我会区间异或,区间最值,区间加法,然后揉在一起?有点恐怖了。

行,看一下题解,写完去学整体二分,这才是对的,我还要复习一些神秘的东西。

我感觉数数是我需要严肃加强的。哎,真是千疮百孔的基础啊!

按位处理,然后那主席树维护一下,没了。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500005;
int n, m;
int b, x, l, r;
int a[N], ncnt, tr[N << 5], sum[N << 5];
int ls[N << 5], rs[N << 5];
void modify(int &p, int hp, int l, int r, int s){
    if (s < l || s > r) 
        return ;
    p = ++ncnt;
    ls[p] = ls[hp];
    rs[p] = rs[hp];
    sum[p] = sum[hp] + 1;
    if (l == r) 
        return ;
    int mid = (l + r) >> 1;
    if (s <= mid) 
        modify(ls[p], ls[hp], l, mid, s);
    else 
        modify(rs[p], rs[hp], mid + 1, r, s);
}
int query(int p, int hp, int l, int r, int s, int t){
    if (t < l || s > r) 
        return 0;
    int cnt = sum[hp] - sum[p];
    if (cnt == 0) 
        return 0;
    if (s <= l && r <= t) 
        return cnt;
    int mid = (l + r) >> 1;
    return query(ls[p], ls[hp], l, mid, s, t) + query(rs[p], rs[hp], mid + 1, r, s, t);
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    int mx = 0;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
        mx = max(mx, a[i]);
    }
    for (int i = 1; i <= n; i++){
        modify(tr[i], tr[i - 1], 0, mx, a[i]);
    }
    for (int cs = 1; cs <= m; cs++){
        cin >> b >> x >> l >> r;
        int ans = 0;
        for (int i = 18; i >= 0; i--){ //贪心寻找每个位置上的异或最大值 
            if (b & (1 << i)){
                if (!query(tr[l - 1], tr[r], 0, mx, ans - x, ans - x + (1 << i) - 1))
                    ans += (1 << i);
            } 
            else{
                if (query(tr[l - 1], tr[r], 0, mx, ans - x + (1 << i), ans - x + (1 << (i + 1)) - 1))
                    ans += (1 << i); 
            }
        }
        cout << (ans ^ b) << '\n';
    }
    return 0;
}

叹口气......虽然进了省选,但是还差不少,努力进队吧,但是很难,省选里要多至少半道题,努力,加油(ง •_•)ง

相关推荐
田里的水稻1 小时前
math_旋转变换
算法·几何学
“愿你如星辰如月”1 小时前
C++11核心特性全解析
开发语言·c++
ada7_1 小时前
LeetCode(python)——94.二叉
python·算法·leetcode·链表·职场和发展
广都--编程每日问1 小时前
c++右键菜单统一转化文件为utf8编码
c++·windows·python
点云SLAM1 小时前
C++包装器之类型擦除(Type Erasure)包装器之小对象优化(SBO, Small Buffer Optimization)示例(5)
c++·内存管理·c++高级应用·c++包装器·类型擦除包装器·内存小对象优化
AI视觉网奇1 小时前
躯体驱动 算法学习笔记
人工智能·算法
不穿格子的程序员1 小时前
从零开始写算法——普通数组类题:数组操作中的“翻转技巧”与“前后缀分解”
数据结构·算法
逝雪Yuki1 小时前
简单多源BFS问题
算法·leetcode·bfs·广度优先遍历
curry____3031 小时前
study in PTA(高精度算法与预处理)(2025.12.3)
数据结构·c++·算法·高精度算法