练板子题目
线段树--区间更新1模板
区间更新的操作为在区间增加权值wei
对应题目POJ - 3468 A Simple Problem with Integers
#include<iostream>
using namespace std;
/****************************线段树区间更新1模板**************************************/
#define ll long long
const int maxn = 100010;
const ll inf =0x3f3f3f3f;
const ll mod=10007;
ll sums; //全局变量记录区间和
ll mins; //全局变量记录区间最值
ll num[maxn]; //原序列
struct Brraacks { //线段树结点
ll left,rigth,sum,Min,lazy; //结点表示的区间[left,right],区间和sum,区间最小值Min,懒惰标记lazy
} army[maxn * 4];
inline void Build(ll left, ll rigth, ll k) { //从第k个结点开始,建立区间[left,right]的结点,并初始化这些结点
army[k].left = left;
army[k].rigth = rigth;
army[k].Min = inf;
army[k].lazy = 0;
army[k].sum=0;
if (left == rigth) return;
ll mid = (left + rigth) >>1;
Build(left, mid, k<<1);
Build(mid + 1, rigth, k<<1|1);
}
inline void Insert(ll wei, ll pos, ll k) { //从第k个结点开始查找,找到区间[pos,pos]并加上值wei
if (army[k].left == army[k].rigth&&army[k].left == pos) {
army[k].sum = wei;
army[k].Min = army[k].sum;
return;
}
ll mid = (army[k].left + army[k].rigth) >>1;
if (pos <= mid) Insert(wei, pos, k<<1);
else Insert(wei, pos, k<<1|1);
army[k].sum = army[k<<1].sum +army[k<<1|1].sum; //回溯修改第k个结点的sum
army[k].Min = min(army[k<<1].Min, army[k<<1|1].Min);
}
inline void pushdown(ll k) { //将第k个结点的懒惰标记推到他的儿子结点,并更新儿子结点的信息
if (army[k].lazy != 0) {
army[k<<1].sum += (army[k<<1].rigth - army[k<<1].left + 1)*army[k].lazy;
army[k<<1|1].sum += (army[k<<1|1].rigth - army[k<<1|1].left + 1)*army[k].lazy;
army[k<<1].lazy += army[k].lazy;
army[k<<1|1].lazy += army[k].lazy;
army[k<<1].Min += army[k].lazy;
army[k<<1|1].Min += army[k].lazy;
army[k].lazy = 0;
}
}
inline void Update(ll wei, ll l, ll r, ll k) { //从第k个结点开始查找,找到区间[l,r],区间内的所有点加上wei
ll left = army[k].left;
ll rigth = army[k].rigth;
if (l <= left&&rigth <= r) {
army[k].sum += (rigth - left + 1)*wei;
army[k].lazy += wei;
army[k].Min += wei;
return;
}
pushdown(k);
ll mid = (left + rigth) >>1;
if (l >= mid + 1) Update(wei, l, r, k<<1|1);
else if (mid >= r) Update(wei, l, r, k<<1);
else {
Update(wei, l, r, k<<1);
Update(wei, l, r, k<<1|1);
}
army[k].sum = army[k<<1].sum + army[k<<1|1].sum;
army[k].Min = min(army[k<<1].Min, army[k<<1|1].Min);
}
inline void Search(ll left, ll rigth, ll k) { //从第k个结点开始查找,找到区间[left,right],返回区间和(最值)
if (left == army[k].left&&rigth == army[k].rigth) {
sums += army[k].sum;
mins = min(mins, army[k].Min);
return;
}
pushdown(k);
ll mid = (army[k].left + army[k].rigth) >>1;
if (rigth <= mid) Search(left, rigth, k<<1);
else if (left >= mid + 1) Search(left, rigth, k<<1|1);
else {
Search(left, mid, k<<1);
Search(mid + 1, rigth, k<<1|1);
}
}
inline void build(ll l,ll r) { //建立(l,r)的线段树
Build(l,r,1);
}
inline void insert(ll wei,ll pos) { //在pos点加权值wei
Insert(wei,pos,1);
}
inline void update(ll wei,ll l,ll r){ //在区间[l,r]内的所有点加上wei
Update(wei,l,r,1);
}
inline ll search(ll l,ll r) { //在区间[l,r]返回区间和(最值)
sums=0;
mins=inf;
Search(l,r,1);
//return sums;
return sums;
}
/****************************线段树区间更新1模板**************************************/
int main() {
int n,q;
char str[3];
int l,r;
ll w;
while(~scanf("%d %d",&n,&q)) {
for(int i=1; i<=n; i++) scanf("%lld",&num[i]);
build(1,n);
for(int i=1; i<=n; i++)insert(num[i],i);
for(int i=1; i<=q; i++) {
scanf("%s",str);
if(str[0]=='Q') {
scanf("%d %d",&l,&r);
ll ans=search(l,r);
printf("%lld\n",ans);
} else {
scanf("%d %d %lld",&l,&r,&w);
update(w,l,r);
}
}
}
return 0;
}
线段树--区间更新2模板
区间更新的操作为在区间增加一个权值wei,或者将区间的权值权值全部设置为wei
对应题目Hihocoder #1080 : 更为复杂的买卖房屋姿势
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
using namespace std;
/**********************线段树区间更新模板2**************************************************/
#define ll long long
const int maxn = 100010;
const ll inf =0x3f3f3f3f;
const ll mod=10007;
ll sums; //全局变量记录区间和
ll mins; //全局变量记录区间最值
ll num[maxn<<1]; //原序列
struct Brraacks { //线段树结点
ll left,rigth,sum,Min,lazy,flag; //结点表示的区间[left,right],区间和sum,区间最小值Min,懒惰标记lazy
} army[maxn * 4];
inline void Build(ll left, ll rigth, ll k) { //从第k个结点开始,建立区间[left,right]的结点,并初始化这些结点
army[k].left = left;
army[k].rigth = rigth;
army[k].Min = inf;
army[k].lazy = 0;
army[k].sum=0;
army[k].flag=0;
if (left == rigth) return;
ll mid = (left + rigth) >>1;
Build(left, mid, k<<1);
Build(mid + 1, rigth, k<<1|1);
}
inline void Insert(ll wei, ll pos, ll k) { //从第k个结点开始查找,找到区间[pos,pos]并加上值wei
if (army[k].left == army[k].rigth&&army[k].left == pos) {
army[k].sum = wei;
army[k].Min = army[k].sum;
return;
}
ll mid = (army[k].left + army[k].rigth) >>1;
if (pos <= mid) Insert(wei, pos, k<<1);
else Insert(wei, pos, k<<1|1);
army[k].sum = army[k<<1].sum +army[k<<1|1].sum; //回溯修改第k个结点的sum
army[k].Min = min(army[k<<1].Min, army[k<<1|1].Min);
}
inline void pushdown(ll k) { //将第k个结点的懒惰标记推到他的儿子结点,并更新儿子结点的信息
if (army[k].lazy != 0) {
if(army[k].flag) {
army[k<<1].sum = (army[k<<1].rigth - army[k<<1].left + 1)*army[k].lazy;
army[k<<1|1].sum = (army[k<<1|1].rigth - army[k<<1|1].left + 1)*army[k].lazy;
army[k<<1].lazy = army[k].lazy;
army[k<<1|1].lazy = army[k].lazy;
army[k<<1].Min = army[k].lazy;
army[k<<1|1].Min = army[k].lazy;
army[k].lazy = 0;
army[k<<1].flag=1;
army[k<<1|1].flag=1;
army[k].flag=0;
} else {
if(army[k<<1].flag) pushdown(k<<1);
if(army[k<<1|1].flag) pushdown(k<<1|1);
army[k<<1].sum += (army[k<<1].rigth - army[k<<1].left + 1)*army[k].lazy;
army[k<<1|1].sum += (army[k<<1|1].rigth - army[k<<1|1].left + 1)*army[k].lazy;
army[k<<1].lazy += army[k].lazy;
army[k<<1|1].lazy += army[k].lazy;
army[k<<1].Min += army[k].lazy;
army[k<<1|1].Min += army[k].lazy;
army[k].lazy = 0;
}
}
}
inline void Update(bool flag,ll wei, ll l, ll r, ll k) { //从第k个结点开始查找,找到区间[l,r],falg为0则区间内的所有点加上wei,flag为1则将区间内的所有点设置为wei
ll left = army[k].left;
ll rigth = army[k].rigth;
if (l <= left&&rigth <= r) {
if(flag) {
army[k].sum = (rigth - left + 1)*wei;
army[k].lazy = wei;
army[k].Min = wei;
army[k].flag=1;
return;
} else {
army[k].sum += (rigth - left + 1)*wei;
army[k].lazy += wei;
army[k].Min += wei;
return;
}
}
pushdown(k);
ll mid = (left + rigth) >>1;
if (l >= mid + 1) Update(flag,wei, l, r, k<<1|1);
else if (mid >= r) Update(flag,wei, l, r, k<<1);
else {
Update(flag,wei, l, r, k<<1);
Update(flag,wei, l, r, k<<1|1);
}
army[k].sum = army[k<<1].sum + army[k<<1|1].sum;
army[k].Min = min(army[k<<1].Min, army[k<<1|1].Min);
}
inline void Search(ll left, ll rigth, ll k) { //从第k个结点开始查找,找到区间[left,right],返回区间和(最值)
if (left == army[k].left&&rigth == army[k].rigth) {
sums += army[k].sum;
mins = min(mins, army[k].Min);
return;
}
pushdown(k);
ll mid = (army[k].left + army[k].rigth) >>1;
if (rigth <= mid) Search(left, rigth, k<<1);
else if (left >= mid + 1) Search(left, rigth, k<<1|1);
else {
Search(left, mid, k<<1);
Search(mid + 1, rigth, k<<1|1);
}
}
inline void build(ll l,ll r) { //建立(l,r)的线段树
Build(l,r,1);
}
inline void insert(ll wei,ll pos) { //在pos点加权值wei
Insert(wei,pos,1);
}
inline void update(ll wei,ll l,ll r,bool flag) { //flag=0则在区间[l,r]内的所有点加上wei
Update(flag,wei,l,r,1); //flag=1则在将区间[l,r]内的所有点设置为wei
}
inline ll search(ll l,ll r) { //在区间[l,r]返回区间和(最值)
sums=0;
mins=inf;
Search(l,r,1);
//return sums;
return sums;
}
/**********************线段树区间更新模板2**************************************************/
int L[maxn],R[maxn];
bool vis[maxn];
map<int,int>maps;
void debug(int n,int m) {
for(int i=1;i<=n;i++){
printf("%d %d\n",maps[L[i]],maps[R[i]]);
}
for(int i=1; i<=m; i++) {
ll sum_=search(i,i);
printf("%lld ",sum_);
}
cout<<endl;
}
int Hash(int n) {
sort(num+1,num+2*n+1);
int tol=0;
for(int i=1; i<=n<<1; i++) {
if(maps[num[i]]==0)
maps[num[i]]=++tol;
}
return tol;
}
int main() {
int n,_L;
while(~scanf("%d %d",&n,&_L)) {
for(int i=1; i<=n; i++) {
scanf("%d %d",&L[i],&R[i]);
num[i]=L[i];
num[n+i]=R[i];
}
memset(vis,0,sizeof(vis));
maps.clear();
int m=Hash(n);
build(1,m);
int cnt=0;
for(int i=1; i<=n; i++) {
int l=maps[L[i]]+1;
int r=maps[R[i]];
update(i,l,r,1);
}
//debug(n,m);
vis[0]=1;
for(int i=1; i<=m; i++) {
ll tmp=search(i,i);
if(vis[tmp]==0) {
cnt++;
vis[tmp]=1;
}
}
printf("%d\n",cnt);
}
return 0;
}