线段树无止尽版
最近在陆陆续续学习线段树 把学习的点滴汇集起来 也许将来对自己和别人都有所帮助!!
首先特别鸣谢NotOnlySuccess (http://www.notonlysuccess.com/?p=978) 我视这位神明为线段树的导师 他的【完全版】造福全人类
Hdu1754 I hate it
单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream>
#include<algorithm>
using namespace std;
int MAXN[4000001],d[4000001];
void PushUp(int rt)
{
MAXN[rt]=max(MAXN[rt<<1],MAXN[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
cin>> MAXN[rt];
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,(rt<<1)+1);
PushUp(rt);
}
void update(int p,int sc,int l,int r,int rt)
{
if(l==r)
{
MAXN[rt]=sc;
return;
}
int m=(l+r)>>1;
if(p<=m)update(p,sc,l,m,rt<<1);
else update(p,sc,m+1,r,(rt<<1)+1);
PushUp(rt);
}
int getmax(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return MAXN[rt];
}
int m=(l+r)>>1;
int ret=0;
if(L<=m)ret=max(ret,getmax(L,R,l,m,rt<<1));
if(R>m)ret=max(ret,getmax(L,R,m+1,r,(rt<<1)+1));
return ret;
}
int main()
{
int n,m,a,b;
char ch;
while(cin>>n>>m)
{
build(1,n,1);
for(int i=0;i<m;i++)
{
cin>>ch>>a>>b;
if(ch=='U')update(a,b,1,n,1);
else cout<<getmax(a,b,1,n,1)<<endl;
}
}
}
/*hdu4027Can you answer these queries线段树
有舰艇队下面有两种操作
0 x y 攻击编号为x到y的舰艇
1 x y 查询编号为x到y的舰艇的耐力和
攻击:被攻击舰艇的耐力降为原来的耐力值的平方根
2^63开方次=1
*/
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long int64;
#define MAXN 100005
int n,m;
struct node
{
int l,r,mid; //区间的左右边界
int cnt,add; //cnt表示区间现在被攻击次数(是最少的区间的某些舰艇被攻击次数更大)add懒惰标记
int64 sum[8];//存区间舰艇被攻击n次的耐力值和
}a[MAXN<<2];
void pushUp(int rt)
{
for(int i=0;i<8;i++)
a[rt].sum[i]=a[rt<<1].sum[i]+a[(rt<<1)|1].sum[i];
}
void build(int l,int r,int rt)
{
a[rt].l=l;
a[rt].r=r;
a[rt].mid=(l+r)>>1;
a[rt].cnt=a[rt].add=0;
if(l==r)
{
scanf("%I64d",&a[rt].sum[0]);
for(int i=1;i<8;i++)
a[rt].sum[i]=sqrt(a[rt].sum[i-1]*1.0);
return;
}
build(l,a[rt].mid,rt<<1);
build(a[rt].mid+1,r,(rt<<1)|1);
pushUp(rt);
}
void pushDown(int rt)
{
if(a[rt].add)
{
a[rt<<1].add+=a[rt].add;
a[(rt<<1)|1].add+=a[rt].add;
a[rt<<1].cnt+=a[rt].add;
a[(rt<<1)|1].cnt+=a[rt].add;
a[rt].add=0;
if(a[rt<<1].cnt>7)a[rt<<1].cnt=7;
if(a[(rt<<1)|1].cnt>7)a[(rt<<1)|1].cnt=7;
}
}
void update(int l,int r,int rt)
{
if(a[rt].l==l&&a[rt].r==r)
{
a[rt].cnt++;
a[rt].add++;
if(a[rt].cnt>7)a[rt].cnt=7;
return;
}
pushDown(rt);
if(r<=a[rt].mid)
update(l,r,rt<<1);
else if(l>a[rt].mid)
update(l,r,(rt<<1)|1);
else
{
update(l,a[rt].mid,rt<<1);
update(a[rt].mid+1,r,(rt<<1)|1);
}
}
int64 query(int l,int r,int rt)
{
if(a[rt].l==l&&r==a[rt].r)
{
if(a[rt].cnt==7||l==r)//重点
return a[rt].sum[a[rt].cnt];
pushDown(rt);
return query(l,a[rt].mid,rt<<1)+query(a[rt].mid+1,r,(rt<<1)|1);
}
pushDown(rt);
if(r<=a[rt].mid)
return query(l,r,rt<<1);
else if(l>a[rt].mid)
return query(l,r,(rt<<1)|1);
else
return query(l,a[rt].mid,rt<<1)+query(a[rt].mid+1,r,(rt<<1)|1);
}
int main()
{
int k=0;
while(scanf("%d",&n)==1)
{
build(1,n,1);
scanf("%d",&m);
printf("Case #%d:\n",++k);
while(m--)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(x>y)swap(x,y);
if(op==0)
update(x,y,1);
else
printf("%I64d\n",query(x,y,1));
}
printf("\n");
}
}
/*
hdu 4046 Panda
题意:给你一个字符串,由'w' 和'b' 组成,对该字符串有俩个操作,
当输入为时,询问该区间[a,b] 内有多少个串为"wbw";
当输入为时,将下标为k的字符改为输入的字符;
分析:
线段树每一个点表示的是以该下标结束的长度为的子串是否为"wbw",
若是,则等于,否则等于,保存在数组a[]中。
以,当进行区间询问时,对[a,b]的询问则应该改为对区间[a+2,b],当然这里对a+2,和b的大小还是要讨论的;
当进行点修改时,则可能要修改三个点,因为改动一个字符时,
会影响到三个长度为的子串,所以有可能进行三次修改
*/
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
#define MAXN 55555
int num[MAXN];
struct node
{
int l,r,c,mid;
}a[MAXN<<2];
void pushUp(int rt)
{
a[rt].c=a[rt<<1].c+a[(rt<<1)|1].c;
}
void build(int l,int r,int rt)
{
a[rt].l=l;
a[rt].r=r;
a[rt].mid=(l+r)>>1;
a[rt].c=0;
if(l==r)
{
a[rt].c=num[l];
return;
}
build(l,a[rt].mid,rt<<1);
build(a[rt].mid+1,r,(rt<<1)|1);
pushUp(rt);
}
void update(int c,int index,int rt)
{
if(a[rt].l==index&&a[rt].r==index)
{
a[rt].c=c;
return;
}
if(a[rt].mid>=index)update(c,index,rt<<1);
else update(c,index,(rt<<1)|1);
pushUp(rt);
}
int query(int l,int r,int rt)
{
if(a[rt].l==l&&a[rt].r==r)return a[rt].c;
if(a[rt].mid>=r)return query(l,r,rt<<1);
else if(a[rt].mid<l)return query(l,r,rt<<1|1);
else
return query(l,a[rt].mid,rt<<1)+query(a[rt].mid+1,r,rt<<1|1);
}
int main()
{
string str;
int n,m,cas,Cas=0,op,x,y;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
cin>>str;
memset(num,0,sizeof(num));
for(int i=2;i<str.size();i++)
if(str[i-2]=='w'&&str[i-1]=='b'&&str[i]=='w')num[i]=1;
build(0,n-1,1);
printf("Case %d:\n",++Cas);
for(int i=0;i<m;i++)
{
scanf("%d",&op);
if(op==0)
{
scanf("%d%d",&x,&y);
if(x+2>y)printf("0\n");
else printf("%d\n",query(x+2,y,1));
}
else
{
char ch;
cin>>x>>ch;
if(str[x]==ch)continue;
str[x]=ch;
if(x>=2&&str[x-2]=='w'&&str[x-1]=='b'&&str[x]=='w')
{update(1,x,1);num[x]=1;}
else if(num[x]==1){update(0,x,1),num[x]=0;}
if(x-1>=0&&x+1<str.size()&&str[x-1]=='w'&&str[x]=='b'&&str[x+1]=='w')
{
update(1,x+1,1);
num[x+1]=1;
}
else if(x+1<str.size()&&num[x+1]==1){update(0,x+1,1),num[x+1]=0;}
if(x+2<str.size()&&str[x]=='w'&&str[x+1]=='b'&&str[x+2]=='w')
{update(1,x+2,1),num[x+2]=1;}
else if(x+2<str.size()&&num[x+2]==1){update(0,x+2,1),num[x+2]=0;}
}
}
}
}