线段树无止尽版

最近在陆陆续续学习线段树  把学习的点滴汇集起来 也许将来对自己和别人都有所帮助!!

首先特别鸣谢NotOnlySuccess (http://www.notonlysuccess.com/?p=978) 我视这位神明为线段树的导师 他的【完全版】造福全人类

Hdu1754 I hate it

单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来

View Code
#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

*/

View Code
#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的大小还是要讨论的;

当进行点修改时,则可能要修改三个点,因为改动一个字符时,

会影响到三个长度为的子串,所以有可能进行三次修改

*/

View Code
#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;}

}

}

}

}



原文地址:https://www.cnblogs.com/sook/p/2135984.html