2024.9.25校测
T1
题目描述
给你一个序列:
-
modify l r x
,将区间 中的每个数修改为 。 -
change l r x
,将区间 中的每个数加上 。 -
query l r
,询问区间 中的和。
输入格式
第
第
接下来
输出格式
对于每个询问操作,输出其结果。
输入样例
3 3
1 2 3
change 1 3 2
modify 3 3 3
query 1 3
输出样例
10
数据规模
对于
对于
题解
典型的线段树题。
考虑一个节点有加标记,要添加改标记,就将加标记清零;如果一个节点有改标记,要添加加标记,直接在原加标记上增加就行了。
完整代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4e5 + 9;
int n, m, t[N << 2], tag_add[N << 2], tag_change[N << 2];
char ch[20];
void buildTree(int id, int L, int R){
if(L == R){
scanf("%lld", &t[id]);
return;
}
int mid = (L + R) >> 1;
buildTree(id << 1, L, mid);
buildTree(id << 1 | 1, mid + 1, R);
t[id] = t[id << 1] + t[id << 1 | 1];
}
void pushdown(int id, int L, int R){
int mid = (L + R) >> 1;
if(tag_change[id]){
tag_add[id << 1] = tag_add[id << 1 | 1] = 0;
t[id << 1] = tag_change[id] * (mid - L + 1);
t[id << 1 | 1] = tag_change[id] * (R - mid);
tag_change[id << 1] = tag_change[id << 1 | 1] = tag_change[id];
tag_change[id] = 0;
}
if(tag_add[id]){
tag_add[id << 1] += tag_add[id];
t[id << 1] += tag_add[id] * (mid - L + 1);
tag_add[id << 1 | 1] += tag_add[id];
t[id << 1 | 1] += tag_add[id] * (R - mid);
tag_add[id] = 0;
}
}
void modify(int id, int L, int R, int qL, int qR, int qx, int type){
pushdown(id, L, R);
if(L == qL && R == qR){
if(type == 1){
tag_add[id] = 0;
t[id] = qx * (R - L + 1);
tag_change[id] = qx;
return;
} else {
t[id] += qx * (R - L + 1);
tag_add[id] += qx;
return;
}
}
int mid = (L + R) >> 1;
if(qR <= mid)
modify(id << 1, L, mid, qL, qR, qx, type);
else if(qL > mid)
modify(id << 1 | 1, mid + 1, R, qL, qR, qx, type);
else{
modify(id << 1, L, mid, qL, mid, qx, type);
modify(id << 1 | 1, mid + 1, R, mid + 1, qR, qx, type);
}
t[id] = t[id << 1] + t[id << 1 | 1];
}
int query(int id, int L, int R, int qL, int qR){
pushdown(id, L, R);
if(L == qL && R == qR)
return t[id];
int mid = (L + R) >> 1;
if(qR <= mid)
return query(id << 1, L, mid, qL, qR);
else if(qL > mid)
return query(id << 1 | 1, mid + 1, R, qL, qR);
else
return query(id << 1, L, mid, qL, mid) + query(id << 1 | 1, mid + 1, R, mid + 1, qR);
}
signed main(){
freopen("setmod.in", "r", stdin);
freopen("setmod.out", "w", stdout);
scanf("%lld%lld", &n, &m);
buildTree(1, 1, n);
for(int i = 1; i <= m; ++i){
int qL, qR, qx;
scanf("%s", ch);
if(ch[0] == 'c'){
scanf("%lld%lld%lld", &qL, &qR, &qx);
if(qL > qR)
continue;
modify(1, 1, n, qL, qR, qx, 2);
} else if(ch[0] == 'm'){
scanf("%lld%lld%lld", &qL, &qR, &qx);
if(qL > qR)
continue;
modify(1, 1, n, qL, qR, qx, 1);
} else {
scanf("%lld%lld", &qL, &qR);
if(qL > qR){
printf("0\n");
continue;
}
printf("%lld\n", query(1, 1, n, qL, qR));
}
}
return 0;
}
T2
题目描述
给出
更准确一点,每个矩形将给出它的左上角和右下角的位置:
这四个数都是整数且满足
我们需要你求:
输入格式
第
接下来
输出格式
输出
输入样例
3
1 1 2 3
1 2 3 3
3 3 4 4
输出样例
11
样例解释
一共有
数据规模
对于
对于
题解
非常模板的扫描线算法,如不知道什么是扫描线,请参考线段树进阶应用学习笔记(一)(2024.7.19)(2024.8.22)
完整代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9;
struct Node{
int l, r, y, op;
} a[N << 1];
bool cmp(Node a, Node b){
return a.y < b.y;
}
int t[N << 2], tag[N << 2], ans, cnt, n;
void pushup(int id, int L, int R){
if(tag[id]){
t[id] = R - L + 1;
return;
}
t[id] = t[id << 1] + t[id << 1 | 1];
}
void modify(int id, int L, int R, int qL, int qR, int qx){
if(qL == L && R == qR){
tag[id] += qx;
pushup(id, L, R);
return;
}
int mid = (L + R) >> 1;
if(qR <= mid)
modify(id << 1, L, mid, qL, qR, qx);
else if(qL > mid)
modify(id << 1 | 1, mid + 1, R, qL, qR, qx);
else {
modify(id << 1, L, mid, qL, mid, qx);
modify(id << 1 | 1, mid + 1, R, mid + 1, qR, qx);
}
pushup(id, L, R);
}
signed main(){
// freopen("area.in", "r", stdin);
// freopen("area.out", "w", stdout);
scanf("%lld", &n);
for(int i = 1; i <= n; i++){
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
a[++cnt] = {x1, x2, y1, 1};
a[++cnt] = {x1, x2, y2 + 1, -1};
}
sort(a + 1, a + cnt + 1, cmp);
for(int i = 1; i <= cnt; i++){
ans += t[1] * (a[i].y - a[i - 1].y);
modify(1, 1, N, a[i].l, a[i].r, a[i].op);
}
printf("%lld", ans);
return 0;
}
T3
题目描述
我看好你哟。
给你一个长度为 n 的序列,有 m 个操作:
-
modify u x
将第 个数修改为 。 -
query l r k
询问区间 中第 小的数 。
输入格式
第
第
接下来
输出格式
对于每个询问操作,输出其结果。
输入样例
5 5
5 2 1 3 4
query 1 4 3
modify 4 5
query 1 4 3
modify 1 3
query 1 4 3
输出样例
3
5
3
提示
数据规模
对于
对于
题解
区间第
先考虑朴素二分,从
那么整体二分就是将几个询问一起二分,首先将询问离线,将
考虑如何修改,考虑值域树状数组,将一个数改为另一个数时,只用将原先的数在树状数组中减
完整代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 9, inf = 1e9 + 7;
struct node{
int x, y, k, type, id;
} q[N * 3], q1[N * 3], q2[N * 3];
int n, m, tot, totx;
int a[N], ans[N];
int c[N * 24];
int lowbit(int p){
return (p & -p);
}
void Add(int x, int v){
if(!x)
return;
while(x < 500005)
c[x] += v, x += lowbit(x);
}
int Ask(int x){
int t = 0;
while(x)
t += c[x], x -= lowbit(x);
return t;
}
int Ask(int l, int r){
if (l > r)
return 0;
return Ask(r) - Ask(l - 1);
}
void solve(int ql, int qr, int L, int R){
if(ql > qr)
return;
if(L == R){
for(int i = ql; i <= qr; i++)
if(q[i].type == 2)
ans[q[i].id] = L;
return;
}
int mid = (L + R) >> 1;
int t1 = 0, t2 = 0;
for(int i = ql; i <= qr; i++){
if(q[i].type == 1){
if(q[i].x <= mid){
Add(q[i].id, q[i].y);
q1[t1++] = q[i];
} else
q2[t2++] = q[i];
} else {
int tt = Ask(q[i].x, q[i].y);
if(tt >= q[i].k)
q1[t1++] = q[i];
else {
q[i].k -= tt;
q2[t2++] = q[i];
}
}
}
for(int i = 0; i < t1; i++)
q[ql + i] = q1[i];
for(int i = 0; i < t2; i++)
q[ql + t1 + i] = q2[i];
for(int i = 0; i < t1; i++)
if(q1[i].type == 1)
Add(q1[i].id, -q1[i].y);
solve(ql, ql + t1 - 1, L, mid);
solve(ql + t1, qr, mid + 1, R);
}
signed main(){
freopen("intkth.in", "r", stdin);
freopen("intkth.out", "w", stdout);
scanf("%lld%lld", &n, &m);
int x, y, k;
char op[5];
for(int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
tot++;
q[tot].x = a[i], q[tot].y = 1, q[tot].type = 1, q[tot].id = i;
}
for(int i = 1; i <= m; i++){
scanf("%s", op);
if(op[0] == 'q'){
scanf("%lld%lld%lld", &x, &y, &k);
tot++;
q[tot].x = x, q[tot].y = y, q[tot].k = k, q[tot].type = 2, q[tot].id = ++totx;
} else {
scanf("%lld%lld", &x, &y);
tot++;
q[tot].x = a[x]; q[tot].y = -1; q[tot].type = 1, q[tot].id = x;
tot++;
a[x] = y;
q[tot].x = a[x]; q[tot].y = 1; q[tot].type = 1, q[tot].id = x;
}
}
solve(1, tot, 0, inf);
for(int i = 1; i <= totx; i++)
printf("%lld\n", ans[i]);
return 0;
}
本文来自博客园,作者:JPGOJCZX,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18431803
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】