2026-01-27~28 hetao1733837 的刷题记录
01-27
LGP4315 月下"毛景树"
原题链接:月下"毛景树"
分析
树剖+线段树,线段树要实现单点修改、区间加、区间赋值、区间最值查询。理论......我真的会写吗?我好🍬啊,在机房大声唱歌......坏了,真不会写了/jk
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, sz[N], top[N], de[N], fa[N], dfn[N], rk[N], ncnt;
struct node{
int mx;
int tag1, tag2;
bool flag;
node():
mx(0), tag1(0), tag2(0), flag(false){}
}tr[N << 2];
int w[N];
struct segtree{
void pushup(int p){
tr[p].mx = max(tr[p << 1].mx, tr[p << 1 | 1].mx);
}
void down(int p, int l, int r){
if (l == r)
return ;
int mid = (l + r) >> 1;
if (tr[p].flag){
tr[p << 1].mx = tr[p].tag2;
tr[p << 1 | 1].mx = tr[p].tag2;
tr[p << 1].tag2 = tr[p].tag2;
tr[p << 1 | 1].tag2 = tr[p].tag2;
tr[p << 1].flag = true;
tr[p << 1 | 1].flag = true;
tr[p << 1].tag1 = 0;
tr[p << 1 | 1].tag1 = 0;
}
if (tr[p].tag1){
tr[p << 1].mx += tr[p].tag1;
tr[p << 1 | 1].mx += tr[p].tag1;
tr[p << 1].tag1 += tr[p].tag1;
tr[p << 1 | 1].tag1 += tr[p].tag1;
}
tr[p].tag1 = 0;
tr[p].tag2 = 0;
tr[p].flag = false;
}
void build(int p, int l, int r){
if (l == r){
tr[p].mx = w[rk[l]];
return ;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
pushup(p);
}
void change(int p, int l, int r, int pos, int val){
if (l == r) {
tr[p].mx = val;
return ;
}
down(p, l, r);
int mid = (l + r) >> 1;
if (pos <= mid)
change(p << 1, l, mid, pos, val);
else
change(p << 1 | 1, mid + 1, r, pos, val);
pushup(p);
}
void modify1(int p, int l, int r, int s, int t, int val){
if (s <= l && r <= t){
tr[p].mx = val;
tr[p].tag2 = val;
tr[p].flag = true;
tr[p].tag1 = 0;
return ;
}
down(p, l, r);
int mid = (l + r) >> 1;
if (s <= mid)
modify1(p << 1, l, mid, s, t, val);
if (t > mid)
modify1(p << 1 | 1, mid + 1, r, s, t, val);
pushup(p);
}
void modify2(int p, int l, int r, int s, int t, int val){
if (s <= l && r <= t){
tr[p].mx += val;
tr[p].tag1 += val;
return ;
}
down(p, l, r);
int mid = (l + r) >> 1;
if (s <= mid)
modify2(p << 1, l, mid, s, t, val);
if (t > mid)
modify2(p << 1 | 1, mid + 1, r, s, t, val);
pushup(p);
}
int query(int p, int l, int r, int s, int t){
if (s <= l && r <= t){
return tr[p].mx;
}
down(p, l, r);
int mid = (l + r) >> 1;
int res = -0x3f3f3f3f;
if (s <= mid)
res = max(res, query(p << 1, l, mid, s, t));
if (t > mid)
res = max(res, query(p << 1 | 1, mid + 1, r, s, t));
return res;
}
}T;
vector<pair<int, int>> e[N];
int son[N];
void dfs1(int u, int pa){
fa[u] = pa;
de[u] = de[pa] + 1;
sz[u] = 1;
for (auto tmp : e[u]){
int v = tmp.first;
if (v == pa)
continue;
w[v] = tmp.second;
dfs1(v, u);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]){
son[u] = v;
}
}
}
void dfs2(int u, int tp){
dfn[u] = ++ncnt;
rk[ncnt] = u;
top[u] = tp;
if (son[u])
dfs2(son[u], tp);
for (auto tmp : e[u]){
int v = tmp.first;
if (v == fa[u] || v == son[u])
continue;
dfs2(v, v);
}
}
void path_modify1(int u, int v, int val){
while (top[u] != top[v]) {
if (de[top[u]] < de[top[v]])
swap(u, v);
T.modify1(1, 1, n, dfn[top[u]], dfn[u], val);
u = fa[top[u]];
}
if (de[u] > de[v])
swap(u, v);
if (u != v)
T.modify1(1, 1, n, dfn[u] + 1, dfn[v], val);
}
void path_modify2(int u, int v, int val){
while (top[u] != top[v]){
if (de[top[u]] < de[top[v]])
swap(u, v);
T.modify2(1, 1, n, dfn[top[u]], dfn[u], val);
u = fa[top[u]];
}
if (de[u] > de[v])
swap(u, v);
if (u != v)
T.modify2(1, 1, n, dfn[u] + 1, dfn[v], val);
}
int path_query(int u, int v){
int res = 0xc0c0c0c0;
while (top[u] != top[v]) {
if (de[top[u]] < de[top[v]])
swap(u, v);
res = max(res, T.query(1, 1, n, dfn[top[u]], dfn[u]));
u = fa[top[u]];
}
if (de[u] > de[v])
swap(u, v);
if (u != v)
res = max(res, T.query(1, 1, n, dfn[u] + 1, dfn[v]));
return res;
}
pair<int, int> edge[N];
int MX[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1, a, b, c; i < n; i++){
cin >> a >> b >> c;
edge[i] = {a, b};
e[a].push_back({b, c});
e[b].push_back({a, c});
}
dfs1(1, 0);
dfs2(1, 1);
for (int i = 1; i < n; i++){
int a = edge[i].first, b = edge[i].second;
if (de[a] > de[b])
MX[i] = a;
else
MX[i] = b;
}
T.build(1, 1, n);
string s;
while (cin >> s){
if (s == "Stop")
break;
if (s == "Change"){
int k, val;
cin >> k >> val;
T.change(1, 1, n, dfn[MX[k]], val);
}
else if (s == "Cover"){
int u, v, val;
cin >> u >> v >> val;
path_modify1(u, v, val);
}
else if (s == "Add"){
int u, v, val;
cin >> u >> v >> val;
path_modify2(u, v, val);
}
else if (s == "Max"){
int u, v;
cin >> u >> v;
cout << path_query(u, v) << '\n';
}
}
}
LGP2209 [USACO13OPEN] Fuel Economy S
原题链接:[USACO13OPEN] Fuel Economy S
分析
和那个 23 年 J 组的 T1 好像......只是说这个题加了一个 G G G 的限制。这个无解其实好判,就是相邻两点(包括加油站和起点终点)之间如果距离比邮箱容量大,那就祭了。剩下的似乎就比较自然了,我们记录剩余油量,然后找油量范围内最小的即可。感觉比较好写但是我不会
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 50005;
struct node{
int x, y, pos;
}inp[N];
bool cmp(node a, node b){
return a.x < b.x;
}
int n, g, b, d;
int stk[N], tp;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> g >> b >> d;
for (int i = 1; i <= n; i++){
cin >> inp[i].x >> inp[i].y;
}
sort(inp + 1, inp + n + 1, cmp);
inp[++n] = {d};
for (int i = 1; i <= n; i++){
while (tp && inp[i].y <= inp[stk[tp]].y){
inp[stk[tp]].pos = i;
tp--;
}
stk[++tp] = i;
}
int ans = 0;
b -= inp[1].x;
int i = 1;
while (i < n){
if (b < 0){
cout << -1;
return 0;
}
if (inp[inp[i].pos].x - inp[i].x <= g){
int tmp = max(0ll, inp[inp[i].pos].x - inp[i].x - b);
ans += tmp * inp[i].y;
b += tmp - (inp[inp[i].pos].x - inp[i].x);
i = inp[i].pos;
}
else{
ans += (g - b) * inp[i].y;
b = g - (inp[i + 1].x - inp[i].x);
i++;
}
}
if (b < 0)
cout << -1;
else
cout << ans;
}
启动文化课了......
01-28
LGP2023 [AHOI2009] 维护序列
原题链接:[AHOI2009] 维护序列
分析
纯纯【模板】线段树 2,改一个读入位置就过了......
正解
cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100005;
int n, m, k, s, t, a[N], P;
struct node{
ll sum[N * 4], tag1[N * 4], tag2[N * 4];
void update(int p){
sum[p] = (sum[p * 2] + sum[p * 2 + 1]) % P;
}
void down(int p, int l, int r, ll a, ll b){ //标记下放
sum[p] = (sum[p] * a + (r - l + 1) * b) % P;
tag1[p] = tag1[p] * a % P;
tag2[p] = (tag2[p] * a + b) % P;
}
void build(int p, int l, int r){
tag1[p] = 1;
tag2[p] = 0; //标记初始化
if (l == r){
sum[p] = a[l];
return ;
}
int mid = (l + r) / 2;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
update(p);
}
ll query(int p, int l, int r, int s, int t){
if (l >= s && r <= t)
return sum[p] % P;
int mid = (l + r) / 2;
down(p * 2, l, mid, tag1[p], tag2[p]);
down(p * 2 + 1, mid + 1, r, tag1[p], tag2[p]);
tag1[p] = 1;
tag2[p] = 0;
ll tmp = 0;
if (s <= mid){
tmp += query(p * 2, l, mid, s, t);
tmp %= P;
}
if (t > mid){
tmp += query(p * 2 + 1, mid + 1, r, s, t);
tmp %= P;
}
return tmp % P;
}
void modify(int p, int l, int r, int s, int t, ll a, ll b){ //对 [s,t] 区间执行( * a + b)
if (l >= s && r <= t){
down(p, l, r, a, b);
return ;
}
int mid = (l + r) / 2;
down(p * 2, l, mid, tag1[p], tag2[p]);
down(p * 2 + 1, mid + 1, r, tag1[p], tag2[p]);
tag1[p] = 1;
tag2[p] = 0;
if (s <= mid)
modify(p * 2, l, mid, s, t, a, b);
if (t > mid)
modify(p * 2 + 1, mid + 1, r, s, t, a, b);
update(p);
}
}T;
int main(){
cin >> n >> m >> P;
for (int i = 1; i <= n; i++)
cin >> a[i];
T.build(1, 1, n);
int opt;
for (int i = 1; i <= m; i++){
cin >> opt >> s >> t;
if (opt == 3)
cout << T.query(1, 1, n, s, t) % P << '\n';
else{
cin >> k;
if (opt == 1)
T.modify(1, 1, n, s, t, k, 0);
else
T.modify(1, 1, n, s, t, 1, k);
}
}
}
LGP6327 区间加区间 sin 和
原题链接:区间加区间 sin 和
分析
还好我上高中了......思考一下,依然维护一个 sin \sin sin 和一个 cos \cos cos,这样的话,区间加可以变成区间 sin \sin sin 乘 cos ( v ) \cos(v) cos(v),区间 cos \cos cos 乘 sin ( v ) \sin(v) sin(v),然后, sin \sin sin 理论上是要合并一下的......怎么说呢?就是那个原有的 cos \cos cos 乘上某个东西之后,直接与 sin \sin sin 乘上之后加和得到新的 sin \sin sin,那我的 cos \cos cos 似乎也要跟着变一下啊......那不如这样,我直接再在代码里排列组合一下,同意赋个值应该就可以了......然后,内置函数的话,复杂度应该不是很大吧......稍考一下......哦,不用担心, O ( 1 ) O(1) O(1) 的。但是,还有一个小问题......哦,没错,要转弧度制......有点吃了......卧槽,不提示是角度制?这么简单?我操!
我是傻逼/ll,yhl 要制裁我了。
妈呀,lz 来了......
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, a[N], m;
struct segtree{
double sums[N << 2], sumc[N << 2];
long long tag[N << 2];
void pushup(int p){
sums[p] = sums[p << 1] + sums[p << 1 | 1];
sumc[p] = sumc[p << 1] + sumc[p << 1 | 1];
}
void calc(int p, double si, double co){
double s = sums[p], c = sumc[p];
sums[p] = s * co + c * si;
sumc[p] = c * co - s * si;
}
void down(int p){
if (!tag[p])
return;
double si = sin(tag[p]), co = cos(tag[p]);
calc(p << 1, si, co);
calc(p << 1 | 1, si, co);
tag[p << 1] += tag[p];
tag[p << 1 | 1] += tag[p];
tag[p] = 0;
}
void build(int p, int l, int r){
if (l == r){
sums[p] = sin(a[l]);
sumc[p] = cos(a[l]);
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 s, int t, int val, double si, double co){
if (s <= l && r <= t){
calc(p, si, co);
tag[p] += val;
return ;
}
down(p);
int mid = (l + r) >> 1;
if (s <= mid)
modify(p << 1, l, mid, s, t, val, si, co);
if (t > mid)
modify(p << 1 | 1, mid + 1, r, s, t, val, si, co);
pushup(p);
}
double query(int p, int l, int r, int s, int t){
if (s <= l && r <= t){
return sums[p];
}
down(p);
int mid = (l + r) >> 1;
double res = 0;
if (s <= mid)
res += query(p << 1, l, mid, s, t);
if (t > mid)
res += query(p << 1 | 1, mid + 1, r, s, t);
return res;
}
}T;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
T.build(1, 1, n);
cin >> m;
for (int cs = 1, op, l, r, v; cs <= m; cs++){
cin >> op >> l >> r;
if (op == 1){
cin >> v;
double si = sin(v), co = cos(v);
T.modify(1, 1, n, l, r, v, si, co);
}
else{
cout << fixed << setprecision(1) << T.query(1, 1, n, l, r) << '\n';
}
}
}
启动浦东!
浦东怎么这么多/ll
LGP3792 由乃与大母神原型和偶像崇拜
原题链接:由乃与大母神原型和偶像崇拜
分析
如果只有和,性质比较弱,那么,如果是平方和、异或和、 2 i 2^i 2i 和、立方和......呢?是不是性质就比较强了?但是可能太大,所以,理论上应该取模......会不会冲突呢?看数据了......那么,还是尝试自己写一下吧......不对,他要维护好几个和!看一眼题解,思考一下......有点炸啊......我会写吗?试试!先不管可能溢出这种情况,先写出来!
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 500005, V = 25000005;
int n, m, a[N];
int aoao[V];
struct segtree{
int sum[N << 2], sum2[N << 2], mn[N << 2], mx[N << 2], tag[N << 2];
void pushup(int p){
sum[p] = (sum[p << 1] + sum[p << 1 | 1]);
sum2[p] = (sum2[p << 1] + sum2[p << 1 | 1]);
mn[p] = min(mn[p << 1], mn[p << 1 | 1]);
mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
}
void down(int p, int l, int r){
if (!tag[p] || l == r)
return ;
int tmp = sum[p];
sum[p] = (sum[p] + (r - l + 1) * tag[p]);
sum2[p] = (sum2[p] + (r - l + 1) * tag[p] * tag[p] + 2 * tag[p] * tmp);
mn[p] = min(mn[p], tag[p]);
mx[p] = max(mx[p], tag[p]);
tag[p] = 0;
pushup(p);
}
void build(int p, int l, int r){
if (l == r){
sum[p] = a[l];
sum2[p] = a[l] * a[l];
mn[p] = a[l];
mx[p] = a[l];
tag[p] = 0;
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 s, int val){
if (l == r){
sum[p] = val;
sum2[p] = val * val;
mn[p] = val;
mx[p] = val;
tag[p] = val;
return ;
}
int mid = (l + r) >> 1;
down(p, l, r);
if (s <= mid)
modify(p << 1, l, mid, s, val);
else
modify(p << 1 | 1, mid + 1, r, s, val);
pushup(p);
}
int query_sum(int p, int l, int r, int s, int t){
if (s <= l && r <= t){
return sum2[p];
}
down(p, l, r);
int mid = (l + r) >> 1;
int res = 0;
if (s <= mid)
res += query_sum(p << 1, l, mid, s, t);
if (t > mid)
res += query_sum(p << 1 | 1, mid + 1, r, s, t);
return res;
}
pair<int, int> query(int p, int l, int r, int s, int t){
if (s <= l && r <= t){
return {mn[p], mx[p]};
}
int mid = (l + r) >> 1;
down(p, l, r);
int maxn = 0xc0c0c0c0, minn = 0x3f3f3f3f;
if (s <= mid){
auto tmp = query(p << 1, l, mid, s, t);
minn = min(minn, tmp.first);
maxn = max(maxn, tmp.second);
}
if (t > mid){
auto tmp = query(p << 1 | 1, mid + 1, r, s, t);
minn = min(minn, tmp.first);
maxn = max(maxn, tmp.second);
}
return {minn, maxn};
}
}T;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
for (int i = 1; i < V; i++){
aoao[i] = (aoao[i - 1] + i * i);
}
cin >> n >> m;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
T.build(1, 1, n);
for (int cs = 1, opt, x, y, l, r; cs <= m; cs++){
cin >> opt;
if (opt == 1){
cin >> x >> y;
T.modify(1, 1, n, x, y);
}
else if (opt == 2){
cin >> l >> r;
auto tmp = T.query(1, 1, n, l, r);
if ((aoao[tmp.second] - aoao[tmp.first - 1]) == T.query_sum(1, 1, n, l, r)){
cout << "damushen" << '\n';
}
else{
cout << "yuanxing" << '\n';
}
}
}
}
咋过了?就是啊,这为啥过了?但是是自己写出来的!没有看题解代码!难道是自然溢出?那数据显然很水了......哦,别骄傲,确实很水......
LGP5069 [Ynoi Easy Round 2015] 纵使日薄西山
原题链接:[Ynoi Easy Round 2015] 纵使日薄西山
分析
单点修改......怎么查?STL 是 hyw ?感觉每次再统计是个很蠢的事,应该尽可能继承前面的答案......思索一下......
看了一眼题解......没太看明白......关掉音乐再看一遍......
就是说,我们发现对于 a x − 1 , a x , a x + 1 a_{x-1},a_x,a_{x+1} ax−1,ax,ax+1,他们分别 − 1 -1 −1,则相对大小不变,那么,我们要做的就是维护一个对于中间 a x a_x ax 的集合,要求互不相邻,然后,讨论相邻情况合并即可......还是没懂
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n, q, a[N];
bool L[N << 2][4], R[N << 2][4];
int sum[N << 2][4];
struct segtree{
void pushup(int p, int l, int r){
int mid = (l + r) >> 1;
if (R[p << 1][0] && L[p << 1 | 1][0]){
if (a[mid] >= a[mid + 1]){
L[p][0] = L[p << 1][0];
R[p][0] = R[p << 1 | 1][1];
sum[p][0] = sum[p << 1][0] + sum[p << 1 | 1][1];
}
else{
L[p][0] = L[p << 1][2];
R[p][0] = R[p << 1 | 1][0];
sum[p][0] = sum[p << 1][2] + sum[p << 1 | 1][0];
}
}
else{
L[p][0] = L[p << 1][0];
R[p][0] = R[p << 1 | 1][0];
sum[p][0] = sum[p << 1][0] + sum[p << 1 | 1][0];
}
if (R[p << 1][1] && L[p << 1 | 1][0]){
if (a[mid] >= a[mid + 1]){
R[p][1] = R[p << 1 | 1][1];
sum[p][1] = sum[p << 1][1] + sum[p << 1 | 1][1];
}
else{
R[p][1] = R[p << 1 | 1][0];
sum[p][1] = sum[p << 1][3] + sum[p << 1 | 1][0];
}
}
else{
R[p][1] = R[p << 1 | 1][0];
sum[p][1] = sum[p << 1][1] + sum[p << 1 | 1][0];
}
if (R[p << 1][0] && L[p << 1 | 1][2]){
if (a[mid] >= a[mid + 1]){
L[p][2] = L[p << 1][0];
sum[p][2] = sum[p << 1][0] + sum[p << 1 | 1][3];
}
else{
L[p][2] = L[p << 1][2];
sum[p][2] = sum[p << 1][2] + sum[p << 1 | 1][2];
}
}
else{
L[p][2] = L[p << 1][0];
sum[p][2] = sum[p << 1][0] + sum[p << 1 | 1][2];
}
if (R[p << 1][1] && L[p << 1 | 1][2]){
if (a[mid] >= a[mid + 1]){
sum[p][3] = sum[p << 1][1] + sum[p << 1 | 1][3];
}
else{
sum[p][3] = sum[p << 1][3] + sum[p << 1 | 1][2];
}
}
else{
sum[p][3] = sum[p << 1][1] + sum[p << 1 | 1][2];
}
}
void build(int p, int l, int r){
if (l == r){
sum[p][0] = a[l];
L[p][0] = R[p][0] = 1;
return ;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
pushup(p, l, r);
}
void modify(int p, int l, int r, int s){
if (l == r){
sum[p][0] = a[l];
return ;
}
int mid = (l + r) >> 1;
if (s <= mid)
modify(p << 1, l, mid, s);
else
modify(p << 1 | 1, mid + 1, r, s);
pushup(p, l, r);
}
}T;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
T.build(1, 1, n);
cin >> q;
for (int cs = 1, x, y; cs <= q; cs++){
cin >> x >> y;
a[x] = y;
T.modify(1, 1, n, x);
cout << sum[1][0] << '\n';
}
}