标准线段树。对于query中第二行的if为何成立,给个解释。就是left和right表示我们访问的区间,l和r表示我们需要访问的区间,如果访问的区间在我们需要访问的区间内,就直接返回访问区间的值。
区间修改模板题,区间修改比单点修改麻烦点,不过理清思路就行。
按照高度分配,初始值为w,线段树记录最大值。每次更新从左往右找。如果h大于2e5,那么建树right为2e5,因为n最大就2e5,所以多的h没用。
这里就没必要用query函数,直接在更新时输出就行。
因为这个牛是往前看的,所以我们要从后面遍历。每次遍历到一个点时,把这个点牛的数量减1,因为我们线段树记录的是牛的区间和。每次遍历都会让一个牛确定,所以区间减1。
这题数据比较大,得用结构体,如果直接数组线段树应该会tle。
其次这题和lostcows是一个思路,从后往前,记录位置。
因为仔细观察数据,y是递增的,然后我们分析问题其实可以得到,我们要求的就是对于这个点,前面有几个点的x值小于等于它的x值的。再换一种想法就是每次有一个点,我们对线段树就更新这个点。用区间维护这个x的个数,然后到后面统计的时候其实就是求区间和。比如我们对于5 1,我们就是求区间1到5的和。我们1和1就是求1到1的和。
这题是区间dp加上线段树。因为是环,所以我们要把它随意切成一个线段。然后求这个线段中连续最大值。那么最大值有哪些情况呢?
一个就是在线段内部,一个就是线段的两边(因为是环,所以可能在线段两头的和是最大值)。对于线段内部,我们定义maxseg维护区间最大值就行,如果是两边的话,我们要用区间和减去最小值minseg。由于有正负数,所以我们还要考虑情况,如果全正数,那么我们maxseg==sum,这时候由于题目知道,我们必须要去掉一个值,那么就让sum-minseg得到,如果有负数,我们可以知道我们至少得去掉一个负数,才会得到 区间最大值。
那么区间最大值该怎么dp到。由于这题有改点操作,所以我们要想到线段树,然后线段树递归是二分的,所以区间最大值可能有左子树,或者右子树,也可能是两者连起来。左右子树最大值很好找,就是maxseg[left]和maxseg[right],但是中间连起来的怎么弄,难道是把这2个maxseg连起来吗?不是, 因为可能中间点有个负数,导致左右子树都不取这个值,导致我们得到的maxseg[rt]中间断开,不是最大连续区间了。所以,我们定义lmax,lmin,rmax,rmin分别用来针对这种情况的最大最小值。对于区间[a,b],lmax表示包含a的最大连续区间,rmax表示包含b的最大连续区间,我们定义left是rt左子树,right是右子树的话,lmax[right]是包含右子树第一个结点的最大连续区间,rmax[left]是包含左子树最后一个结点的最大连续区间,这两个加起来就是包含中间值的最大连续区间。
那么lmax和rmax怎么维护,lmax表示包含a的最大区间的话,对于rt结点,他的lmax[rt]也有2个情况,一个就是lmax[left](这个最大值不包含右子树),另一个是sum[leftt]+lmax[rgiht](这个最大值包含右子树的点,为何要sum,因为lmax定义是包含a的最大连续区间,用sum保证左子树全取到,才能去右子树上的点)其他的同理。
这题麻烦的地方:1.分析下一次我们要out哪个位置的孩子。2.如何求约数的数量和。3.怎么避免超时
对于1,我们知道当前位置为k,那么他右边i位置的孩子在线段树上什么位置,(k+i-1)%mod(mod是剩余学生数)为何减一,因为k位置的孩子已经out。对于左边位置i的孩子位置是(k+i)%mod,为何不减一,因为在左边,线段树遍历不会遍历到右边。
对于2,约束一个个求会超时,那么我们整体求,看看这个数是哪些数的约数。
对于3,string函数会超时,建议改为char name[15]。还有就是最好用scanf和printf,时间也相差很多。
染色形线段树。
推荐博客
https://blog.csdn.net/iwts_24/article/details/81603603?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1e5+5;
int vis[35] = {
0 };
int lazy[MAXN * 4] = {
0 };
int tree[MAXN * 4];
int L, T, O,ans;
void init() {
for (int i = 0;i < MAXN * 4;i++) {
tree[i] = 1;
}
memset(lazy, 0, sizeof lazy);
memset(vis, 0, sizeof vis);
}
void push_down(int rt) {
lazy[rt * 2] = lazy[rt];
lazy[rt * 2 + 1] = lazy[rt];
tree[rt * 2] = lazy[rt];
tree[rt * 2 + 1] = lazy[rt];
lazy[rt] = 0;
}
void update(int l, int r, int tar, int left, int right, int rt) {
if (l <= left && r >= right) {
lazy[rt] = tar;
tree[rt] = tar;
return;
}
if (lazy[rt]) {
push_down(rt);
}
int mid = (left + right) / 2;
if (l <= mid)update(l, r, tar, left, mid, 2 * rt);
if (r > mid)update(l, r, tar, mid + 1, right, 2 * rt + 1);
if (tree[2 * rt] == tree[2 * rt + 1]) {
tree[rt] = tree[rt * 2];
}
else {
tree[rt] = -1;
}
}
void query(int l, int r, int left, int right, int rt) {
if (l <= left && r >= right) {
if (tree[rt] == 0)return;//这题要不要无所谓
if (tree[rt] == -1) {
if (lazy[rt])push_down(rt);//要不要无所谓,因为tree和lazy改变有2个方式,一个是update,那么这2个一起改,一个是pushdown,但是也是一起改的。所以tree为-1时,lazy必定是0.
int mid = (left + right) / 2;
if (l <= mid)query(l, r, left, mid, 2 * rt);
if (r > mid)query(l, r, mid + 1, right, 2 * rt + 1);
}
else {
if (vis[tree[rt]] == 0) {
ans++;
vis[tree[rt]] = 1;
}
}
return;
}
if (lazy[rt])push_down(rt);
int mid = (left + right) / 2;
if (mid >= l)query(l, r, left, mid, 2 * rt);
if (r > mid)query(l, r, mid + 1, right, 2 * rt + 1);
}
int main() {
std::ios::sync_with_stdio(false);
while (cin>>L>>T>>O) {
init();
while (O--) {
char c;
cin >> c;
if (c == 'C') {
int a, b, c;
cin >> a >> b >> c;
if (b < a) {
int tmp = b;
b = a;
a = tmp;
}
update(a, b, c, 1, L, 1);
}
if (c == 'P') {
memset(vis, 0, sizeof vis);
ans = 0;
int a, b;
cin >> a >> b;
if (b < a) {
int tmp = b;
b = a;
a = tmp;
}
query(a, b, 1, L, 1);
cout << ans << endl;
}
}
}
}
就是求区间最大最小值差,经典线段树只要维护最大值和最小值就行。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 2e5+5;
struct Tree {
int maxn, minn, l, r;
}tree[MAXN*4];
int num[MAXN];
int N, Q;
void buildtree(int left, int right, int rt) {
tree[rt].l = left;
tree[rt].r = right;
if (left == right) {
tree[rt].maxn = num[left];
tree[rt].minn = num[left];
return;
}
int mid = (left + right) / 2;
buildtree(left, mid, rt * 2);
buildtree(mid + 1, right, 2 * rt + 1);
tree[rt].maxn = max(tree[rt *2].maxn, tree[rt * 2 + 1].maxn);
tree[rt].minn = min(tree[rt * 2].minn, tree[rt * 2 + 1].minn);
}
int maxx = 0, minx = 1e9;
void query(int l, int r, int left, int right, int rt) {
if (l <= left && r >= right) {
maxx = max(maxx, tree[rt].maxn);
minx = min(minx, tree[rt].minn);
return;
}
int mid = (left + right) / 2;
if (l <= mid)query(l, r, left, mid, 2 * rt);
if (r > mid)query(l, r, mid + 1, right, 2 * rt + 1);
}
int main() {
std::ios::sync_with_stdio(false);
cin >> N >> Q;
for (int i = 1;i <= N;i++) {
cin >> num[i];
}
buildtree(1, N, 1);
for (int i = 1;i <= Q;i++) {
maxx =0 , minx = 1e9;
int a, b;
cin >> a >> b;
query(a, b, 1, N, 1);
//cout << maxx << " "<
cout << maxx - minx << endl;
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 1e5+5;
long long tree[MAXN * 4];
long long lazy[MAXN * 4] = {
0 };
int N, Q;
long long num[MAXN];
void buildtree(int left, int right, int rt) {
if (left == right) {
tree[rt] = num[left];
return;
}
int mid = (left + right) / 2;
buildtree(left, mid, rt * 2);
buildtree(mid + 1, right, rt * 2 + 1);
tree[rt] = tree[rt * 2] + tree[rt * 2 + 1];
}
void push_down(long long len,int rt) {
tree[rt * 2] += lazy[rt] * (len - len / 2);
tree[rt * 2 + 1] += lazy[rt] * (len / 2);
lazy[2 * rt] += lazy[rt];
lazy[2 * rt + 1] += lazy[rt];
lazy[rt] = 0;
}
void update(int l, int r, int tar, int left, int right, int rt) {
if (l <= left && r >= right) {
lazy[rt] += tar;
tree[rt] += (right-left+1)*tar;
return;
}
if (lazy[rt])push_down(right-left+1,rt);
int mid = (left + right) / 2;
if(l<=mid)update(l, r, tar, left, mid, rt * 2);
if(r>mid)update(l, r, tar, mid + 1, right, rt * 2 + 1);
tree[rt] = tree[rt * 2] + tree[rt * 2 + 1];
}
long long query(int l, int r, int left, int right, int rt) {
if (l <= left && r >= right)return tree[rt];
if (lazy[rt])push_down(right - left + 1, rt);
int mid = (left + right) / 2;
long long ans = 0;
if (l <= mid)ans += query(l, r, left, mid, 2 * rt);
if (r > mid)ans += query(l, r, mid + 1, right, 2 * rt + 1);
return ans;
}
int main() {
std::ios::sync_with_stdio(false);
cin >> N >> Q;
for (int i = 1;i <= N;i++) {
cin >> num[i];
}
buildtree(1, N, 1);
while (Q--) {
char a;
cin >> a;
if (a == 'Q') {
int b, c;
cin >> b >> c;
cout << query(b, c, 1, N, 1)<<endl;
}
if (a == 'C') {
int b, c, d;
cin >> b >> c >> d;
update(b, c, d, 1, N, 1);
}
}
return 0;
}