网站怎么做组织图/站内推广
文章目录
- 前言
- 时间安排及成绩
- 题解
- A. 倒水(bfs + dp)
- B. 让他们连通(整体二分 + 按秩合并并查集 / kruskal重构树)
- C. 通信网络(线段树合并 + 二分)
- D. 3SUM(扫描线 + 线段树)
前言
T1没做出来的一集。。。
时间安排及成绩
- 7:40 开题
- 7:40 - 7:45 T1看懂了,感觉像广搜,但是复杂度好像不对。又好像是背包,但是物品的体积和权值好像会算错。不是很会。看了一眼T2,好像是线段树分治的板子??
- 7:45 - 8:00 T1还是不咋会,果断开T2。发现这题好像也不是线段树分治。想到答案肯定满足单调性,于是可以二分。但是不能对所有询问都二分,因此可以整体二分??中间也想过kruskal重构树,但感觉不太行。没想太多,感觉整体二分加上按秩合并并查集应该就行。直接开写。
- 8:00 - 8:20 想了一会儿按秩合并并查集,然后写到一般发现我不会就算维护了点的连通性也没法 O ( 1 ) O(1) O(1) 判断一段区间是否联通!!!这。。。感觉好难啊。
- 8:20 - 8:40 冷静思考,发现我们可以求出每个点和它前一个点最早的联通时间,那么一段区间联通的答案就是区间最大值。
- 8:40 - 9:00 改完了,调了调,把样例都过了。感觉没啥问题,于是直接扔了。
- 9:00 - 9:10 回去看T1,感觉还是没啥清晰的思路。直接开T3!!
- 9:10 - 9:20 T2看懂了,发现明显具有单调性,可以直接二分答案 + 线段树合并。时间复杂度应该是 n l o g 2 n nlog^2n nlog2n,感觉可过就直接开写。
- 9:20 - 10:10 写完了,但是样例答案是负数??回去重看了一遍题发现确实说明了答案有可能是负数。把二分的边界改一下就把所有样例过了??但是这个大样例跑的有点慢啊。
- 10:10 - 10:40 放到oj上测试一下,发现确实过不去,会TLE。考虑一下卡常。最开始想的是不二分,直接用一个指针,然后每次检验。指针只会单减因此复杂度不会炸??但是被我构个菊花直接卡炸了。然后就想到可以对每个点分别二分求出答案,最后答案就是所有点的最小值。然后每个点二分时右边界可以根据其它点的答案缩小。也算卡常吧。
- 10:40 - 11:10 改完了,大样例跑的飞快。检查一下,感觉没啥问题直接扔了。
- 11:10 - 11:15 5min把T4看了,然后5min写了个40分跑路。回去看T1
- 11:15 - 11:30 自认为想到一个很对的思路,但是写起来又感觉不会了。果断写暴力。
- 11:30 - 11:55 暴力好难写,写完后编译。CE??!!感觉没问题啊。
- 11:55 - 12:00 最后都没看出来啥问题,交了个CE的程序。
估分:0 + 100 + 100 + 40 = 240
得分:0 + 100 + 100 + 40 = 240
rk6
T3赛后卡双log好像没卡掉我。。
题解
A. 倒水(bfs + dp)
分析:
感觉是很好的一道题。
题意已经很清楚了,就不赘述了。
首先直接搜索需要纪录四个状态 桶里的水量和三个杯子中的水量。状态数是 1 0 5 × 10 0 3 10^5 \times 100^3 105×1003 的,显然过不去。我们想要减少状态数。
又不难发现实际上这个问题好像可以对应成背包问题:水量看作体积,操作数是代价。但是 被子倒满水后要不要倒掉 显然就成了一个问题。我们想让最后不用的那一次不倒,其他用的时候需要倒掉。这似乎没法在dp里体现。
正解是有一条性质:设操作(5) 为使用若干次操作(1),(2),(4),然后让被子中有一些水量。那么最优方案一定是进行若干次操作 (5),每个操作(5)后将所有有水的杯子中的水都倒入桶中。最后进行一次操作(5),但是可以将部分水倒入桶中。
这个打表证明是对的。但是我们也可以感性理解一下:对于一个杯子里的水而言,如果它不倒入桶中,并且以后还要使用,那么一定会在下次往里倒水前将里面的水倒掉。由于它里面的水不会倒入桶中,又因为交换操作对于操作数没有影响。因此我们可以把这个杯子中的水被倒掉的操作移到前面,形成 除了要往桶中倒水的杯子,其他杯子都是空的状态。并且这个状态不会影响最优性。如果这个杯子以后不使用了,那么可以看作使用最后一次操作(5)后只将部分水倒入桶中的状态。
那么就可以 b f s bfs bfs O ( 10 0 3 ) O(100^3) O(1003) 搜出所有状态,然后计算出 c o s t 1 cost_1 cost1 和 c o s t 2 cost_2 cost2 数组。接着用 c o s t 1 cost_1 cost1 和 c o s t 2 cost_2 cost2 转移 d p dp dp 即可。
复杂度 O ( 300 × n ) O(300 \times n) O(300×n)
CODE:
#include<bits/stdc++.h>
using namespace std;
typedef pair< int, int > PII;
const int N = 105;
const int M = 1e5 + 10;
int n, num[4], dis[N][N][N];
int cost1[N * 3], cost2[N * 3]; // 全部到入,部分倒入
int dp[M], f[M];
bool vis[N][N][N];
struct state {int x, y, z; // 三杯水的质量分别为 x, y, z
};
queue< state > qq;
PII pour(int x, int y, int lx, int ly) {return make_pair(x - min(x, ly - y), y + min(x, ly - y));
}
void ins(int x, int y, int z) {cost1[x + y + z] = min(cost1[x + y + z], dis[x][y][z] + (x > 0) + (y > 0) + (z > 0));if(x > 0) cost2[x] = min(cost2[x], dis[x][y][z] + 1);if(y > 0) cost2[y] = min(cost2[y], dis[x][y][z] + 1);if(z > 0) cost2[z] = min(cost2[z], dis[x][y][z] + 1);if(x + y > 0) cost2[x + y] = min(cost2[x + y], dis[x][y][z] + 2);if(x + z > 0) cost2[x + z] = min(cost2[x + z], dis[x][y][z] + 2);if(y + z > 0) cost2[y + z] = min(cost2[y + z], dis[x][y][z] + 2);if(x + y + z > 0) cost2[x + y + z] = min(cost2[x + y + z], dis[x][y][z] + 3);
}
int main() {cin >> num[1] >> num[2] >> num[3] >> n;sort(num + 1, num + 3 + 1);memset(cost1, 0x3f, sizeof cost1);memset(cost2, 0x3f, sizeof cost2);memset(dis, 0x3f, sizeof dis);vis[0][0][0] = 1; qq.push((state) {0, 0, 0});dis[0][0][0] = 0;while(!qq.empty()) {state u = qq.front(); qq.pop();int x = u.x, y = u.y, z = u.z;ins(x, y, z); // 更新答案 if(!vis[num[1]][y][z]) { // 1操作 vis[num[1]][y][z] = 1;dis[num[1]][y][z] = dis[x][y][z] + 1;qq.push((state) {num[1], y, z});}if(!vis[x][num[2]][z]) {vis[x][num[2]][z] = 1;dis[x][num[2]][z] = dis[x][y][z] + 1;qq.push((state) {x, num[2], z});}if(!vis[x][y][num[3]]) {vis[x][y][num[3]] = 1;dis[x][y][num[3]] = dis[x][y][z] + 1;qq.push((state) {x, y, num[3]});}if(!vis[0][y][z]) { // 2操作 vis[0][y][z] = 1;dis[0][y][z] = dis[x][y][z] + 1;qq.push((state) {0, y, z});}if(!vis[x][0][z]) {vis[x][0][z] = 1;dis[x][0][z] = dis[x][y][z] + 1;qq.push((state) {x, 0, z});}if(!vis[x][y][0]) { vis[x][y][0] = 1;dis[x][y][0] = dis[x][y][z] + 1;qq.push((state) {x, y, 0});}PII g; int p, q;g = pour(x, y, num[1], num[2]); // x -> yp = g.first, q = g.second;if(!vis[p][q][z]) {vis[p][q][z] = 1;dis[p][q][z] = dis[x][y][z] + 1;qq.push((state) {p, q, z});}g = pour(y, x, num[2], num[1]); // y -> xp = g.first, q = g.second;if(!vis[q][p][z]) {vis[q][p][z] = 1;dis[q][p][z] = dis[x][y][z] + 1;qq.push((state) {q, p, z});}g = pour(x, z, num[1], num[3]); // x -> zp = g.first, q = g.second;if(!vis[p][y][q]) {vis[p][y][q] = 1;dis[p][y][q] = dis[x][y][z] + 1;qq.push((state) {p, y, q});}g = pour(z, x, num[3], num[1]); // z -> xp = g.first, q = g.second;if(!vis[q][y][p]) {vis[q][y][p] = 1;dis[q][y][p] = dis[x][y][z] + 1;qq.push((state) {q, y, p});}g = pour(y, z, num[2], num[3]); // y -> zp = g.first, q = g.second;if(!vis[x][p][q]) {vis[x][p][q] = 1;dis[x][p][q] = dis[x][y][z] + 1;qq.push((state) {x, p, q});}g = pour(z, y, num[3], num[2]); // z -> yp = g.first, q = g.second;if(!vis[x][q][p]) {vis[x][q][p] = 1;dis[x][q][p] = dis[x][y][z] + 1;qq.push((state) {x, q, p});} }memset(dp, 0x3f, sizeof dp);memset(f, 0x3f, sizeof f);dp[0] = 0;for(int i = 0; i <= n; i ++ ) {f[i] = min(f[i], dp[i]);for(int j = 1; j <= num[1] + num[2] + num[3]; j ++ ) {if(i + j <= n) dp[i + j] = min(dp[i + j], dp[i] + cost1[j]);if(i + j <= n) f[i + j] = min(f[i + j], dp[i] + cost2[j]);}}for(int i = 1; i <= n; i ++ ) {if(f[i] > 20000000) printf("-1 ");else printf("%d ", f[i]);}return 0;
}
/*
20 5 15 10 13 13 7 19 2 22 3 17 8 15 11 9 17 4 22 2 19 6 17 9 11 15 6 20 4 21 4 19 7 13 13 8 18 6 21 3 21 5 15 11 10 16 8 19 5 23 3 17 9 12 14 10 17 7 23 2*/
B. 让他们连通(整体二分 + 按秩合并并查集 / kruskal重构树)
原题链接
分析:
S o l 1 : Sol1: Sol1:
一个关键想法是我们可以 只关心一个点 i i i 和点 i − 1 i - 1 i−1最早的连通时间 t i t_i ti即可。
那么对于区间 [ l , r ] [l, r] [l,r] 而言,它最早的连通的时间就是 m a x i = l + 1 r t i max_{i = l + 1}^{r}t_i maxi=l+1rti。
对于 t i t_i ti 的求法,我们可以整体二分 + 可撤销并查集 即可。我们使用 按秩合并 并查集就行。
时间复杂度 O ( q × l o g 2 q × l o g 2 n ) O(q \times log_2q \times log_2n) O(q×log2q×log2n)。
S o l 2 : Sol2: Sol2:
考虑维护两个点的最早连通时间,也可以使用 Kruskal重构树。然后查询只需要求 l c a lca lca 即可。
时间复杂度 O ( n × l o g 2 n ) O(n \times log_2n) O(n×log2n)
下面的代码是第一种解法的代码。
CODE:
#include<bits/stdc++.h> // 只需求出每个点和它前面的点最早的联通时间
using namespace std;
const int N = 2e5 + 10;
int n, m, qc, u[N], v[N], o;
int g[N], lt[N], rt[N], Link[N];
int mx[N][21];
struct Q {int l, r;
}q[N];
struct inform { // 合并信息 int x, y, hx, hy; // x 合到 y 上, x原来的树高是 hx, y原来的树高是 hy
};
int bin[N], h[N]; // 父亲, 树高
stack< inform > s;
int Find(int x) {return x == bin[x] ? x : Find(bin[x]);
}
void Merge(int x, int y) { // 合并 x, y int f1 = Find(x), f2 = Find(y);if(f1 != f2) {if(h[f1] > h[f2]) swap(f1, f2);s.push((inform) {f1, f2, h[f1], h[f2]});o ++;bin[f1] = f2;if(h[f1] == h[f2]) h[f2] ++;}
}
void back(int cnt) { // 撤回 cnt 次 while(cnt --) {inform t = s.top(); s.pop();int x = t.x, y = t.y, hx = t.hx, hy = t.hy;bin[x] = x;h[x] = hx; h[y] = hy;}
}
void solve(int l, int r, int ql, int qr) {if(l == r) {Merge(u[l], v[l]); // 合并 for(int i = ql; i <= qr; i ++ ) Link[g[i]] = l;return ;}int mid = (l + r >> 1);o = 0;for(int i = l; i <= mid; i ++ ) {int U = u[i], V = v[i];Merge(U, V);}int lc = 0, rc = 0; for(int i = ql; i <= qr; i ++ ) {int p = g[i];if(Find(p - 1) == Find(p)) lt[++ lc] = p;else rt[++ rc] = p;}for(int i = 1; i <= lc; i ++ ) g[i + ql - 1] = lt[i];for(int i = 1; i <= rc; i ++ ) g[lc + ql + i - 1] = rt[i];back(o); // 撤回操作 solve(l, mid, ql, ql + lc - 1); // 左 solve(mid + 1, r, ql + lc, qr);// 右
}
int query(int l, int r) {int k = log2(r - l + 1);return max(mx[l][k], mx[r - (1 << k) + 1][k]);
}
void build_st() {for(int i = 1; i <= n; i ++ ) mx[i][0] = Link[i];for(int i = 1; (1 << i) <= n; i ++ ) {for(int j = 1; j + (1 << i) - 1 <= n; j ++ ) {mx[j][i] = max(mx[j][i - 1], mx[j + (1 << (i - 1))][i - 1]);}}
}
int main() {scanf("%d%d%d", &n, &m, &qc);for(int i = 1; i <= n; i ++ ) bin[i] = i, h[i] = 1;for(int i = 1; i <= m; i ++ ) {scanf("%d%d", &u[i], &v[i]);}for(int i = 1; i <= qc; i ++ ) {scanf("%d%d", &q[i].l, &q[i].r);}for(int i = 1; i <= n; i ++ ) g[i] = i;solve(1, m, 1, n);build_st();for(int i = 1; i <= qc; i ++ ) {int ans;if(q[i].l == q[i].r) ans = 0;else ans = query(q[i].l + 1, q[i].r);printf("%d ", ans);}return 0;
}
C. 通信网络(线段树合并 + 二分)
分析:
题意:
给你一个 n n n 个点的树,点有点权 w i w_i wi。若现在有一个数 P P P,那么对于一个点 x x x,它的负荷就是所有满足一下两个条件的简单路径条数:
- u , v u,v u,v 是路径的两个端点,并且满足 w u ≤ w x + P w_u \leq w_x + P wu≤wx+P, w v ≤ w x + P w_v \leq w_x + P wv≤wx+P。
- x x x 在路径 u → v u \to v u→v 上。
现在想让所有点的负荷都小于 K K K,求最大的 P P P。
不难看出, P P P 越大,每个点的负荷只会增大,不会减小。具有单调性,因此可以 二分答案。 我们考虑如何检验:
若给定一个 P P P,那么每个点的负荷计算就很简单了。对于一个点 x x x,只需要能快速查询它的子树里小于等于 w x + P w_x + P wx+P 的数的个数即可。那么可以做 线段树合并,并在 值域线段树 里二分。这样可以计算出端点都在 x x x 子树里的路径个数。对于一个端点在子树里,一个端点在子树外的路径,显然可以拿所有小于等于 w x + P w_x + P wx+P 的数的个数减去 x x x 的子树里的个数,这样能算出来 x x x 子树外能成为端点的点数,然后和子树里的相乘即可。这样时间复杂度就是 O ( n × l o g 2 2 w ) O(n \times log^2_2w) O(n×log22w) 的。
我们发现这样过不去,还要卡一下常:
由于 K K K 给定,因此可以对每个点求出满足条件的最大的 P P P,然后最终答案就是所有点的答案取 m i n min min。对每个点求这样的 P P P 可以二分,这样时间复杂度也是 O ( n × l o g 2 2 w ) O(n \times log^2_2w) O(n×log22w) 的。但是注意到每个点二分时右端点不必开满,可以令当前求出的答案的最小值作为端点。这样也是一个剪枝。这样做之后就跑的特别快了,最后没有被卡掉。
CODE:
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N = 3e5 + 10;
const int M = 3e6 + 10;
typedef long long LL;
int n, w[N], u, v;
int pre[M], tot, rt[N];
int ans[N], res = 1e8, now;
vector< int > E[N];
LL k;
struct SegmentTree {int ls, rs, cnt;#define ls(x) t[x].ls#define rs(x) t[x].rs#define cnt(x) t[x].cnt
}t[N * 25];
void update(int p) {cnt(p) = cnt(ls(p)) + cnt(rs(p));
}
void ins(int p, int lp, int rp, int pos) {if(lp == rp) {cnt(p) ++;return ;}int mid = (lp + rp >> 1);if(pos <= mid) {if(!ls(p)) ls(p) = ++ tot;ins(ls(p), lp, mid, pos);}else {if(!rs(p)) rs(p) = ++ tot;ins(rs(p), mid + 1, rp, pos);}update(p);
}
int query(int p, int lp, int rp, int pos) {if(lp == rp) return (lp == pos ? cnt(p) : 0);int mid = (lp + rp >> 1);if(pos <= mid) return query(ls(p), lp, mid, pos);else return cnt(ls(p)) + query(rs(p), mid + 1, rp, pos);
}
int Merge(int p, int q, int lp, int rp) {if(!p || !q) return (p ^ q);if(lp == rp) {cnt(p) += cnt(q);return p;}int mid = (lp + rp >> 1);ls(p) = Merge(ls(p), ls(q), lp, mid);rs(p) = Merge(rs(p), rs(q), mid + 1, rp);update(p);return p;
}
bool check(int x, int fa, int p) {int o = (p + w[x] >= w[x] ? 1 : 0); LL res = 0;for(auto v : E[x]) {if(v == fa) continue;int c = query(rt[v], 1, 2e6, p + w[x]);res += 1LL * o * c;o += c; }res += 1LL * o * ((p + w[x] >= 0 ? pre[w[x] + p] : 0) - o);return res < k;
}
void dfs(int x, int fa) { // x 作为中转站的答案 for(auto v : E[x]) {if(v == fa) continue;dfs(v, x);}int l = -1e6, r = now, mid, res = -1;while(l <= r) {mid = (l + r >> 1);if(check(x, fa, mid)) res = mid, l = mid + 1;else r = mid - 1;}ans[x] = res; now = res;for(auto v : E[x]) {if(v == fa) continue;rt[x] = Merge(rt[x], rt[v], 1, 2e6);}
}
void solve() { // 检验 p 是否合法 弄完再清空 for(int i = 1; i <= n; i ++ ) {rt[i] = ++ tot;ins(rt[i], 1, 2e6, w[i]);}dfs(1, 0);for(int i = 1; i <= n; i ++ ) {res = min(res, ans[i]);}
}
int main() {scanf("%d%lld", &n, &k);int maxw = 0;for(int i = 1; i <= n; i ++ ) {scanf("%d", &w[i]);pre[w[i]] ++;maxw = max(maxw, w[i]);}for(int i = 1; i < n; i ++ ) {scanf("%d%d", &u, &v);E[u].pb(v); E[v].pb(u);}for(int i = 1; i < M; i ++ ) pre[i] += pre[i - 1];now = 1e6; solve();printf("%d\n", res);return 0;
}
正解是单 l o g log log 的。首先对于它没有使用线段树合并,而是 按照 d f s dfs dfs 序由小到大建主席树。那么一个点的子树信息也可以在 d f s dfs dfs 序列中的一段区间中查询。正解也是按照上面这种对每个点求最大的 P P P,然后所有点取 m i n min min 得到答案。考虑如果二分答案然后用主席树检验,时间复杂度也是 O ( n × l o g 2 2 w ) O(n \times log^2_2w) O(n×log22w) 的。然后它就是把所有区间都拿出来,一起在线段树上二分减去一个 l o g log log。具体写法没仔细看,但是大概思路就是这。
D. 3SUM(扫描线 + 线段树)
原题链接
分析:
题意说的很清楚了,不在赘述。
直接说正解吧:
我们对最大值在那一段进行分讨,然后答案取最优:
- 最大值在中间一段。那么可以把中间一段往两边延伸,发现中间那段的答案不变,两边段的答案单调不增。因此这种情况下最优值就是 [ l , l ] [l, l] [l,l], [ l + 1 , r − 1 ] [l + 1, r - 1] [l+1,r−1], [ r , r ] [r, r] [r,r] 的最大值之和。
- 最大值在左边段。如果我们求出 [ l , r ] [l, r] [l,r] 中最大值的最左边位置 x x x,那么第一段的右端点应该大于等于 x x x。我们考虑如果左段的右端点是 r t rt rt,那么要把 [ r t + 1 , r ] [rt + 1, r] [rt+1,r] 分成两端。如果右段的左端点为 l t lt lt,那么三段就是 [ l , r t ] [l, rt] [l,rt], [ r t + 1 , l t − 1 ] [rt + 1, lt - 1] [rt+1,lt−1], [ l t , r ] [lt, r] [lt,r]。不难发现,这时可以将左段向右延伸直到中间段的长度为 1 1 1。这样左段,右段的答案不变,中间段的答案只会变得更优。因此我们得出结论:对于最大值在左段的情况,中间段的长度一定为 1 1 1。因此如果中间段为 [ p , p ] [p, p] [p,p],那么中间段和右段的答案就是 h p = a p + m a x i = p + 1 r a i h_p =a_p + max_{i = p + 1}^{r}a_i hp=ap+maxi=p+1rai,我们需要维护 区间中 h h h 的最小值。这个可以用 线段树 + 单调栈维护 维护。具体来讲,我们对 r r r 扫描线,然后维护一个单调栈。如果 a r > a s t o p a_r > a_{s_{top}} ar>astop,就将栈顶弹出。那么 [ s t o p − 1 , s t o p ) [s_{top - 1},s_{top}) [stop−1,stop) 区间的 h h h 值将会加上 a r − a s t o p a_r - a_{s_{top}} ar−astop 。特别的,由于每个数刚入栈时后边没有数,因此它的 h h h 值是正无穷。那么每次对于第一个栈顶我们将它的 h h h 值改为 a s t o p + a r a_{s_{top}} + a_r astop+ar 即可。然后对于所有右端点为当前 r r r 的区间 [ l , r ] [l, r] [l,r],我们在栈中二分出第一个大于 l l l 的位置 p o s pos pos,这是 [ l , r ] [l, r] [l,r] 区间里最靠左的最大值的位置。在线段树上查询 [ p o s + 1 , r ] [pos + 1, r] [pos+1,r] 的最小值并加上 a p o s a_{pos} apos更新这个询问的答案即可。
- 最大值在右边段。将序列和询问区间反转一下就能变成上一种情况。
时间复杂度 O ( n × l o g 2 n ) O(n \times log_2n) O(n×log2n)。
CODE:
#include<bits/stdc++.h> // 扫描线 + 线段树 + 单调栈
#define pb push_back
#define MP make_pair
using namespace std;
typedef pair< int, int > PII;
const int N = 3e5 + 10;
const int INF = 4e8;
int n, qc, a[N], ans[N], mx[N][21];
vector< PII > vec[N];
struct Q {int l, r, id;
}q[N];
void build_st() {for(int i = 1; i <= n; i ++ ) mx[i][0] = a[i];for(int i = 1; (1 << i) <= n; i ++ ) for(int j = 1; j + (1 << i) - 1 <= n; j ++ ) mx[j][i] = max(mx[j][i - 1], mx[j + (1 << (i - 1))][i - 1]);
}
int query(int l, int r) {int k = log2(r - l + 1);return max(mx[l][k], mx[r - (1 << k) + 1][k]);
}
struct SegmentTree {int l, r, mn, tag;#define l(x) t[x].l#define r(x) t[x].r#define mn(x) t[x].mn#define tag(x) t[x].tag
}t[N * 4];
void build(int p, int l, int r) {l(p) = l, r(p) = r;mn(p) = INF; tag(p) = 0;if(l == r) return ;int mid = (l + r >> 1);build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r);
}
void update(int p) {mn(p) = min(mn(p << 1), mn(p << 1 | 1));
}
void spread(int p) {if(tag(p)) {tag(p << 1) += tag(p); tag(p << 1 | 1) += tag(p);mn(p << 1) += tag(p); mn(p << 1 | 1) += tag(p); tag(p) = 0;}
}
void change(int p, int l, int r, int c) {if(l <= l(p) && r >= r(p)) {mn(p) += c; tag(p) += c;return ;}spread(p);int mid = (l(p) + r(p) >> 1);if(l <= mid) change(p << 1, l, r, c);if(r > mid) change(p << 1 | 1, l, r, c);update(p);
}
void ins(int p, int pos, int c) {if(l(p) == r(p)) {mn(p) = c;return ;}int mid = (l(p) + r(p) >> 1);if(pos <= mid) ins(p << 1, pos, c);else ins(p << 1 | 1, pos, c);update(p);
}
int ask(int p, int l, int r) {if(l <= l(p) && r >= r(p)) return mn(p);spread(p);int mid = (l(p) + r(p) >> 1);if(r <= mid) return ask(p << 1, l, r);else if(l > mid) return ask(p << 1 | 1, l, r);else return min(ask(p << 1, l, r), ask(p << 1 | 1, l, r));
}
void solve() { // 对 r 扫描线 int stk[N], Top = 0; // 单调栈 for(int r = 1; r <= n; r ++ ) {if(r != 1) ins(1, r - 1, a[r - 1] + a[r]);// 先把 r - 1修改了 while(Top > 0 && a[r] > a[stk[Top]]) {int x = stk[Top]; Top --;int l = (Top == 0 ? 1 : stk[Top]);if(x - 1 >= l) change(1, l, x - 1, a[r] - a[x]);}stk[++ Top] = r;for(auto qy : vec[r]) {int l = qy.first, idx = qy.second;int p = lower_bound(stk + 1, stk + Top + 1, l) - (stk); // 第一个大于等于l的位置 int x = stk[p];if(x + 1 <= r) ans[idx] = min(ans[idx], a[x] + ask(1, x + 1, r));} }
}
int main() {scanf("%d%d", &n, &qc);for(int i = 1; i <= n; i ++ ) {scanf("%d", &a[i]);}for(int i = 1; i <= qc; i ++ ) {scanf("%d%d", &q[i].l, &q[i].r);q[i].id= i;}build_st();for(int i = 1; i <= qc; i ++ ) ans[i] = a[q[i].l] + a[q[i].r] + query(q[i].l + 1, q[i].r - 1);for(int i = 1; i <= qc; i ++ ) {vec[q[i].r].pb(MP(q[i].l, q[i].id));}build(1, 1, n);solve();reverse(a + 1, a + n + 1);for(int i = 1; i <= n; i ++ ) {vector< PII > tmp;swap(tmp, vec[i]);}for(int i = 1; i <= qc; i ++ ) {vec[n - q[i].l + 1].pb(MP(n - q[i].r + 1, q[i].id));}build(1, 1, n);solve();for(int i = 1; i <= qc; i ++ ) printf("%d\n", ans[i]);return 0;
}
相关文章:

2024西安铁一中集训DAY27 ---- 模拟赛((bfs,dp) + 整体二分 + 线段树合并 + (扫描线 + 线段树))
文章目录 前言时间安排及成绩题解A. 倒水(bfs dp)B. 让他们连通(整体二分 按秩合并并查集 / kruskal重构树)C. 通信网络(线段树合并 二分)D. 3SUM(扫描线 线段树) 前言 T1没做出…...

STM32F401VET6 PROTEUS8 ILI9341 驱动显示及仿真
stm32cubemx新建工程代码,并生成工程 设置gpio 设置SPI 其他的参考stm32默认设置 然后编辑驱动代码 ili9341.h #ifndef ILI9341_H #define ILI9341_H#include <stdbool.h> #include <stdint.h>#include "glcdfont.h" #include "stm32…...

抖音视频素材网站有哪些?非常好用的5个抖音视频素材库分享
在打造引人入胜的抖音视频时,选择高品质的视频素材至关重要。优选的素材不仅能够显著提升视频的吸引力,还能让你的作品在众多视频中突出重围。对于抖音创作者而言,让我们探索一些备受推崇的视频素材平台,帮助你制作出既专业又引人…...

【数据结构】链式二叉树的实现和思路分析及二叉树OJ
【数据结构】链式二叉树的实现和思路分析及二叉树OJ 🔥个人主页:大白的编程日记 🔥专栏:数据结构 文章目录 【数据结构】链式二叉树的实现和思路分析及二叉树OJ前言一.链式二叉树的定义及结构二.链式二叉树的遍历2.1前序遍历2.2中…...

项目成功秘诀:工单管理系统如何加速进程
国内外主流的10款项目工单管理系统对比:PingCode、Worktile、浪潮云工单管理系统、华为企业智能工单系统、金蝶云苍穹、紫光软件管理系统、Jira、Asana、ServiceNow、Smartsheet。 在管理日益复杂的个人项目时,找到一款能够真正符合需求的管理软件&#…...

OpenGauss和GaussDB有何不同
OpenGauss和GaussDB是两个不同的数据库产品,它们都具有高性能、高可靠性和高可扩展性等优点,但是它们之间也有一些区别和相似之处。了解它们之间的关系、区别、建议、适用场景和如何学习,对于提高技能和保持行业敏感性非常重要。本文将深入探…...

星环科技携手东华软件推出一表通报送联合解决方案
随着国家金融监督管理总局“一表通”试点工作的持续推进,星环科技携手东华软件推出了基于星环科技分布式分析型数据库ArgoDB和大数据基础平台TDH的一表通报送联合解决方案,并已在多地实施落地中得到充分验证。 星环科技与东华软件作为战略合作伙伴&…...

YOLOv10环境搭建、训练自己的目标检测数据集、实际验证和测试
1 环境搭建 1.1 在官方仓库的给定的使用python3.9版本,则使用conda创建对应虚拟环境。 conda create -n yolov10 python3.9 1.2 切换到对应虚拟环境 conda activate yolov10 1.3 在指定目录下克隆yolov10官方仓库代码 git clone https://github.com/THU-MIG/yo…...

Harmony Next -- 通用标题栏:高度自定义,可设置沉浸式状态,正常状态下为:左侧返回、居中标题,左中右均可自定义视图。
hm_common_title_bar OpenHarmony三方库中心仓:https://ohpm.openharmony.cn/#/cn/detail/common_title_bar 介绍 一款通用标题栏,支持高度自定义,可设置沉浸式状态,正常状态下为:左侧返回、居中标题,左…...

甄选范文“论数据分片技术及其应用”软考高级论文,系统架构设计师论文
论文真题 数据分片就是按照一定的规则,将数据集划分成相互独立、正交的数据子集,然后将数据子集分布到不同的节点上。通过设计合理的数据分片规则,可将系统中的数据分布在不同的物理数据库中,达到提升应用系统数据处理速度的目的。 请围绕“论数据分片技术及其应用”论题…...

【elementui】记录el-table设置左、右列固定时,加大滚动条宽度至使滚动条部分被固定列遮挡的解决方法
当前elementui版本:2.8.2 现象:此处el-table__body-wrapper默认的滚动条宽度为8px,我加大到10px,如果不设置fixed一切正常,设置fixed后会被遮挡一点 el-table__fixed-right::before, .el-table__fixed::before 设置…...

Python人工智能:一、语音合成和语音识别
在Python中,语音合成(Text-To-Speech, TTS)和语音识别(Speech-To-Text, STT)是两个非常重要的功能,它们在人工智能、自动化、辅助技术以及许多其他领域都有广泛的应用。下面将分别介绍这两个领域在Python中…...

C/C++进阶 (8)哈希表(STL)
个人主页:仍有未知等待探索-CSDN博客 专题分栏:C 本文着重于模拟实现哈希表,并非是哈希表的使用。 实现的哈希表的底层用的是线性探测法,并非是哈希桶。 目录 一、标准库中的哈希表 1、unordered_map 2、unordered_set 二、模…...
2024电赛H题参考方案(+视频演示+核心控制代码)——自动行驶小车
目录 一、题目要求 二、参考资源获取 三、TI板子可能用到的资源 1、环境搭建及工程移植 2、相关模块的移植 四、控制参考方案 1、整体控制方案视频演示 2、视频演示部分核心代码 五、总结 一、题目要求 小编自认为:此次控制类类型题目的H题,相较于往年较…...

设计模式14-享元模式
设计模式14-享元模式 由来动机定义与结构代码推导特点享元模式的应用总结优点缺点使用享元模式的注意事项 由来动机 在很多应用中,可能会创建大量相似对象,例如在文字处理器中每个字符对象。在这些场景下,如果每个对象都独立存在,…...

Javascript中canvas与svg详解
Canvas 在JavaScript中,<canvas> 元素用于在网页上绘制图形,如线条、圆形、矩形、图像等。它是一个通过JavaScript和HTML的<canvas>元素来工作的绘图表面。<canvas> 元素自身并不具备绘图能力,它仅仅提供了一个绘图环境&a…...

【BUG】已解决:No Python at ‘C:Users…Python Python39python. exe’
No Python at ‘C:Users…Python Python39python. exe’ 目录 No Python at ‘C:Users…Python Python39python. exe’ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰,211科班…...

Flink SQL 的工作机制
前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出,一段查询 SQL / 使用TableAPI 编写的程序(以下简称 TableAPI 代码)从输入到编译为可执行的 JobGraph 主要经历如下几个阶段: 将 SQL文本 / TableAPI 代码转化为逻辑执…...

[AI Mem0] 源码解读,带你了解 Mem0 的实现
Mem0 的 CRUD 到底是如何实现的?我们来看下源码。 使用 先来看下,如何使用 Mem0 import os os.environ["OPENAI_API_KEY"] "sk-xxx"from mem0 import Memorym Memory()# 1. Add: Store a memory from any unstructured text re…...

【LLM】-10-部署llama-3-chinese-8b-instruct-v3 大模型
目录 1、模型下载 2、下载项目代码 3、启动模型 4、模型调用 4.1、completion接口 4.2、聊天(chat completion) 4.3、多轮对话 4.4、文本嵌入向量 5、Java代码实现调用 由于在【LLM】-09-搭建问答系统-对输入Prompt检查-CSDN博客 关于提示词注入…...

C语言 之 理解指针(4)
文章目录 1. 字符指针变量2. 数组指针变量2.1 对数组指针变量的理解2.2 数组指针变量的初始化 3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用 5. 函数指针数组 1. 字符指针变量 我们在前面使用的主要是整形指针变量,现在要学…...

Java设计模式—单例模式(Singleton Pattern)
目录 一、定义 二、应用场景 三、具体实现 示例一 示例二 四、懒汉与饿汉 饿汉模式 懒汉模式 五、总结 六、说明 一、定义 二、应用场景 单例模式的应用场景主要包括以下几个方面: 日志系统:在应用程序中,通常只需要一个日…...

AV1帧间预测(二):运动补偿
运动补偿(Motion Compensation,MC)是帧间预测最基础的工具,AV1支持两种运动补偿方式,一种是传统的平移运动补偿,另一种是仿射运动补偿。下面分别介绍这两种运动补偿方法。 平移运动补偿 平移运动补偿是最传统的运动补偿方式,H.26…...

数学建模(5)——逻辑回归
一、二分类 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklea…...

【C++高阶】:深入探索C++11
✨ 心似白云常自在,意如流水任东西 🌏 📃个人主页:island1314 🔥个人专栏:C学习 🚀 欢迎关注:👍点赞 Ǵ…...

6. 自定义Docker镜像
如何自定义Docker镜像:从基础到实践 Docker作为一个容器化平台,使得应用的打包、分发和运行变得更加高效和便捷。本文将详细介绍如何自定义一个Docker镜像,包括镜像的构成、分层原理、创建自定义镜像的具体步骤,并演示如何打包和…...

「12月·长沙」人工智能与网络安全国际学术会议(ISAICS 2024)
人工智能与网络安全国际学术会议(ISAICS 2024)将于2024年12月20日-2024年12月22日在湖南长沙召开。会议中发表的文章将会被收录,并于见刊后提交EI核心索引。会议旨在在为国内与国际学者搭建交流平台,推进不同学科领域的融合发展,就当今人工智能与网络安全范畴内各学…...

【技术支持案例】使用S32K144+NSD8381驱动电子膨胀阀
文章目录 1. 前言2. 问题描述3. 理论分析3.1 NSD8381如何连接电机3.2 S32K144和NSD8381的软件配置 4.测试验证4.1 测试环境4.2 测试效果4.3 测试记录 1. 前言 最近有客户在使用S32K144NSD8381驱动电子膨胀阀时,遇到无法正常驱动电子膨胀阀的情况。因为笔者也是刚开…...

第二期:集成电路(IC)——智能世界的微观建筑大师
嘿,小伙伴们!👋 我是你们的老朋友小竹笋,一名热爱创作和技术的工程师。上一期我们聊了聊AI芯片,这次我们要深入到更微观的层面,来探究集成电路(IC)的世界。准备好一起探索了吗&#…...

基于物联网的区块链算力网络,IGP/BGP协议
目录 基于物联网的区块链算力网络 IGP/BGP协议 IGP(内部网关协议) BGP(边界网关协议) 内部使用ISP的外部使用BGP的原因 一、网络规模和复杂性 二、路由协议的特性 三、满足业务需求 四、结论 基于物联网的区块链算力网络 通 过 多个物联网传感器将本地计算…...