区间加法、区间乘法、区间替换、区间幂次查询
//
// main.cpp
// 区间操作集锦_区间加法、区间乘法对查询区间平方和的影响
//
// Created by 陈冉飞 on 2019/8/14.
// Copyright © 2019 陈冉飞. All rights reserved.
//
#include <iostream>
using namespace std;
#define mod 10007
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))
#define maxn 400050
int flag[maxn],x[maxn];
int n,q,a,b,c,d,i;
void pushup(int k){
if (flag[k<<1] == 0 || flag[k<<1|1] == 0) flag[k] = 0;
else if(x[k<<1] != x[k<<1|1]) flag[k] = 0;
else flag[k] = 1,x[k] = x[k<<1];
}
void pushdown(int k){
if (flag[k]) {
x[k<<1] = x[k];
x[k<<1|1] = x[k];
flag[k<<1] = flag[k<<1|1] = 1;
flag[k] = 0;
}
}
void update(int k,int l,int r,int num,int gl,int gr,int val){
//区间修改都是要区间覆盖的问题
if (flag[k] && gl <= l && r <= gr) {
if (num == 1) x[k] = (x[k] + val)%mod;
else if(num == 2) x[k] = (x[k]*val)%mod;
else x[k] = val;
return;
}
pushdown(k);
int mid = (l+r)>>1;
if (gl <= mid) update(k<<1, l, mid, num, gl, gr, val);
if (gr >= mid + 1) update(k<<1|1, mid+1, r, num, gl, gr, val);
pushup(k);
}
int query(int k,int l,int r,int gl,int gr,int val){
int f_ans = 0;
if (flag[k] && gl <= l && r <= gr) {
int ans = 1;
//通过循环算次方
for (i = 1; i <= val; i++) ans = (ans*x[k])%mod;
ans = (ans*(r-l+1))%mod;
return ans%mod;
}
pushdown(k);
int mid = (l+r)>>1;
if (gl <= mid) f_ans += query(k<<1, l, mid, gl, gr, val);
if (gr >= mid+1) f_ans += query(k<<1|1, mid+1, r, gl, gr, val);
return f_ans%mod;
}
int main(int argc, const char * argv[]) {
while (~scanf("%d%d",&n,&q) && n != 0) {
//先初始化,由于x是储存原值的数组,
cl(x, 0);cl(flag, 1);
while (q--) {
scanf("%d%d%d%d",&a,&b,&c,&d);
if (a<=3 && a>=1) update(1,1,n,a,b,c,d);
else printf("%d\n",query(1,1,n,b,c,d));
}
}
return 0;
}
区分区间加法、区间替换
hdu1698
注意这个题是区间都替换成某个值,然后向下pushdown的时候直接将维护的值变成区间长度*变成的值即可。
注意多组数据记得在每次开始的时候初始化数组(忘初始化wa了一发才想起来)
//
// main.cpp
// 区间改为某个值_hdu1698
//
// Created by 陈冉飞 on 2019/8/19.
// Copyright © 2019 陈冉飞. All rights reserved.
//
#include <iostream>
using namespace std;
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))
typedef long long ll;
#define maxn 100010
int T,n,q,sum[maxn<<2],c[maxn<<2],tl,tr,tx,kase = 1;
void pushup(int k){
sum[k] = sum[k<<1]+sum[k<<1|1];
}
void pushdown(int k,int nl,int nr){
if (c[k]) {
sum[k<<1] = nl*c[k];
sum[k<<1|1] = nr*c[k];
c[k<<1] = c[k<<1|1] = c[k];
c[k] = 0;
}
}
void build(int k,int l,int r){
if (l == r) {sum[k] = 1;return;}
int mid = (l+r)>>1;
build(k<<1, l, mid);
build(k<<1|1, mid+1, r);
pushup(k);
}
void update(int k,int l,int r,int gl,int gr,int x){
if (gl <= l && r <= gr) {
sum[k] = x*(r-l+1);
c[k] = x;
return;
}
int mid = (l+r)>>1;
pushdown(k,mid-l+1,r-mid);
if (gl <= mid) update(k<<1, l, mid, gl, gr, x);
if (gr >= mid+1) update(k<<1|1, mid+1, r, gl, gr, x);
pushup(k);
}
int main(int argc, const char * argv[]) {
for (scanf("%d",&T); T; T--) {
cl(sum, 0);cl(c, 0);
scanf("%d%d",&n,&q);
build(1, 1, n);
while (q--) {
scanf("%d%d%d",&tl,&tr,&tx);
update(1, 1, n, tl, tr, tx);
}
printf("Case %d: The total value of the hook is %d.\n",kase++,sum[1]);
}
return 0;
}
poj3468
这个在pushdown的时候要将sum加上增加量(也就是区间长度乘上要加的那个值),不能直接替换。
//
// main.cpp
// 线段树_区间修改、区间求和_poj3468
//
// Created by 陈冉飞 on 2019/8/13.
// Copyright © 2019 陈冉飞. All rights reserved.
//
#include <iostream>
//#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 100050
ll sum[maxn*4],add[maxn*4];
int n,m,i,b,c,d;
char s[10];
void build(int k,int l,int r){
add[k] = 0; //所有将add标记数组都初始化为零
if (l == r) {scanf("%lld",&sum[k]);return;}
int mid = (l+r)>>1;
build(k<<1, l, mid);
build(k<<1|1, mid+1, r);
sum[k] = sum[k<<1]+sum[k<<1|1];
}
void pushdown(int k,int lnum,int rnum){ //传过来的是对下面的区间长度的改变
if(add[k]){
sum[k<<1] += (ll)lnum*add[k]; //把左右枝都加上相应的值
sum[k<<1|1] += (ll)rnum*add[k];
//把值传到底下
add[k<<1] += add[k];
add[k<<1|1] += add[k];
add[k] = 0;
}
return;
}
void change(int k,int l,int r,int gl,int gr,int x){
//直接区间覆盖即可,此时只要区间包含
if (gl <= l && r <= gr) {sum[k] += (r-l+1)*x;add[k] += x;return;}
int mid = (l+r)>>1;
//在此处有一个向下pushdown的操作,将底下的区间都改变
pushdown(k, mid-l+1, r-mid);
if (gl <= mid) change(k<<1, l, mid, gl, gr, x); //只要gl<=mid,就更改左半段,因为代表左半段有他的部分
if (gr >= mid+1) change(k<<1|1, mid+1, r, gl, gr, x);
sum[k] = sum[k<<1]+sum[k<<1|1];
return;
}
ll query(int k,int l,int r,int gl,int gr){
if (gl <= l && r <= gr) return sum[k];
int mid = (l+r)>>1;
//注意查询的时候也有pushdown的操作
pushdown(k, mid-l+1, r-mid);
ll ans = 0;
if (gl <= mid) ans+= query(k<<1, l, mid, gl, gr);
if (gr >= mid+1) ans += query(k<<1|1, mid+1, r, gl, gr);
return ans;
}
int main(int argc, const char * argv[]) {
scanf("%d%d",&n,&m);
build(1,1,n);
while (m--) {
scanf("%s",s);
if (s[0] == 'Q'){scanf("%d%d",&b,&c);printf("%lld\n",query(1, 1, n, b, c));}
else {scanf("%d%d%d",&b,&c,&d);change(1, 1, n, b, c, d);}
}
return 0;
}
区间覆盖
hdu3577
区间覆盖问题,就是注意pushup的时候是选最大值。
注意这个储存最后结果的ans向量要记得刷新,(数组刷新了,向量忘记clear。。。)
还有输出格式
//
// main.cpp
// 区间覆盖、区间查找_hdu3577
//
// Created by 陈冉飞 on 2019/8/19.
// Copyright © 2019 陈冉飞. All rights reserved.
//
//#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000010
int sum[maxn<<2],add[maxn<<2],T,k,q,tl,tr,kase = 1; //sum为覆盖次数,add为lazy标记
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))
#include <vector>
vector<int>ans;
void pushup(int k){
sum[k] = max(sum[k<<1],sum[k<<1|1]);
}
void pushdown(int k){
if (add[k]) {
add[k<<1] += add[k];
add[k<<1|1] += add[k];
sum[k<<1] += add[k];
sum[k<<1|1] += add[k];
add[k] = 0;
}
}
int query(int k,int l,int r,int gl,int gr){
int ret = 0;
if (gl <= l && r <= gr) return sum[k];
int mid = (l+r)>>1;
pushdown(k);
if (gl <= mid) ret = max(ret,query(k<<1, l, mid, gl, gr));
if (gr >= mid+1) ret = max(ret, query(k<<1|1, mid+1, r, gl, gr));
return ret;
}
void update(int k,int l,int r,int gl,int gr){
if (gl <= l && r <= gr) {
sum[k] += 1;
add[k] += 1;
return;
}
pushdown(k);
int mid = (l+r)>>1;
if (gl <= mid) update(k<<1, l, mid, gl, gr);
if (gr >= mid+1) update(k<<1|1, mid+1, r, gl, gr);
pushup(k);
}
int main(int argc, const char * argv[]) {
for (scanf("%d",&T); T; T--) {
cl(sum,0);cl(add,0);ans.clear();
scanf("%d%d",&k,&q);
for (int i = 0; i < q; i++) {
scanf("%d%d",&tl,&tr);
if (query(1, 1, 1000000, tl, tr-1) < k) {
ans.push_back(i);
update(1, 1, 1000000, tl, tr-1);
}
}
printf("Case %d:\n",kase++);
for (int i = 0; i <ans.size(); i++) cout<<ans[i]+1<<" ";
cout<<endl<<endl;
}
return 0;
}