首先是建树:
const int MAXN = 1005;//定义 MAXM 为线段最大长度
int Tree[4*MAXN];// Data数组为 main 函数中读入的内容,Tree数组为需要查询的数的信息(如和、最值等),树的空间大小为线段最大长度的四倍!四倍!四倍!
int Data[MAXN];
void Build(int temp,int left,int right){//传入的参数为 temp:当前需要建立的结点;left:当前需要建立的左端点;right:当前需要建立的右端点。
if(left==right){//当左端点等于右端点即建立叶子结点时,直接给数组信息赋值
Tree[temp] = Data[left];
return ;
}
int mid = left + (right-left)/2; // mid为中间点,左儿子结点为 [left,mid] ,右儿子结点为 [mid+1,right];
Build(temp<<1,left,mid);
Build(temp<<1|1,mid+1,right);
Tree[temp] = max(Tree[temp<<1],Tree[temp<<1|1]);//递归返回时用儿子结点更新父节点,此处可进行更新最大值、最小值、区间和等操作
}
单点修改以及对应的区间查询:
void Updata(int temp,int left,int right,int tempt,int value){//tempt为需要修改的叶子结点左端点,value为需要修改成的值;
if(left == right){
Tree[temp] = value;
return ;
}
int mid = left + (right-left)/2;
if(tempt<=mid)Updata(temp<<1,left,mid,tempt,value);//若需要更新的叶子结点在当前结点的左儿子结点的范围内,则递归更新左儿子结点
else Updata(temp<<1|1,mid+1,right,tempt,value);//否则更新右儿子结点
Tree[temp] = max(Tree[temp<<1],Tree[temp<<1|1]);//递归回之后用儿子结点更新父节点(此处是区间最大值)
}
int query(int temp,int left,int right,int ql,int qr){//区间查询
if(qr<left || ql>right)return -1;//若当前结点和需要查找的区间不相交,则返回一个对于区间查询无关的值(如求和时返回0,求最大值时返回-1等)
if(ql<=left && qr>=right)return Tree[temp]; //若当前结点的区间被需要查询的区间覆盖,则返回当前结点的信息
int mid = left + (right-left)/2;
return max(query(temp<<1,left,mid,ql,qr),query(temp<<1|1,mid+1,right,ql,qr));
}
区间修改以及相应的查询:
区间修改用到了lazy的思想,即当一个区间需要更新时,只递归更新到那一层结点,并将其下层结点所需要更新的信息保存在数组中,然后返回,只有当下次遍历到那个结点(更新过程中或查询过程中),才将那个结点的修改信息传递下去,这样就避免了区间修改的每个值的修改。
区间加值:
int add[4*MAXN];//记录点是否有更新信息。
void Pushdown(int temp,int left,int right){//Pushdown函数,将temp结点的信息传递到左右子节点上
add[temp<<1] += add[temp]; //左右儿子结点均加上父节点的更新值
add[temp<<1|1] += add[temp];
int mid = left + (right-left)/2;
Tree[temp<<1] += add[temp]*(mid-left+1);//左右儿子结点均按照需要加的值总和更新结点信息
Tree[temp<<1|1] += add[temp]*(right-mid);
add[temp] = 0;//信息传递完之后就可以将父节点的更新信息删除
}
void Updata(int temp,int left,int right,int ql,int qr,int value){//ql、qr为需要更新的区间左右端点,value为需要增加的值。
if(ql<=left && qr>=right){//与单点更新一样,当当前结点被需要更新的区间覆盖时
add[temp] += value; //更新该结点的更新信息
Tree[temp] += value*(right-left+1);//更新该结点信息
return ;//根据lazy思想,由于不需要遍历到下层结点,因此不需要继续向下更新,直接返回
}
if(add[temp])Pushdown(temp,left,right);
int mid = left + (right-left)/2;
if(ql<=mid)Updata(temp<<1,left,mid,ql,qr,value);//当需更新区间在当前结点的左儿子结点内,则更新左儿子结点
if(qr>mid)Updata(temp<<1|1,mid+1,right,ql,qr,value); //当需更新区间在当前结点的右儿子结点内,则更新右儿子结点
Tree[temp] = Tree[temp<<1]+Tree[temp<<1|1];//递归回上层时一步一步更新回父节点
}
long long query(int temp,int left,int right,int ql,int qr){ //ql、qr为需要查询的区间
if(ql<=left && qr>=right)return Tree[temp];//若当前结点覆盖区间即为需要查询的区间,则直接返回当前结点的信息
if(add[temp])PushDown(temp,left,right); //将当前结点的更新信息传递给其左右子节点
int mid = left + (right-left)/2;
long long ans = 0; //所需查询的结果
if(ql<=m)ans += query(temp<<1,left,mid,ql,qr); //若所需查询的区间与当前结点的左子节点有交集,则结果加上查询其左子节点的结果
if(qr>m)ans += query(temp<<1|1,mid+1,right,ql,qr);//若所需查询的区间与当前结点的右子节点有交集,则结果加上查询其右子节点的结果
return ans;
}
区间改值(其实只是Pushdow函数和Update中修改部分与区间加值不同,并多了一个判断数组):
int Change[4*MAXN];//记录节点改变信息
bool book[4*MAXN];//记录节点是否有改变要传递
void Pushdown(int temp,int left,int right){//Pushdown和区间加值不同,改值时修改结点信息只需要对修改后的信息求和即可,不用加上原信息
Change[temp<<1] = Change[temp];
Change[temp<<1|1] = Change[temp];
book[temp<<1] = true;
book[temp<<1|1] = true;
book[temp] = false;
int mid = left + (right-left)/2;
Tree[temp<<1] = Change[temp]*(mid-left+1);
Tree[temp<<1|1] = Change[temp]*(right-mid);
}
void Updata(int temp,int left,int right,int ql,int qr,int value){
if(ql<=left && qr>=right){ //同样更新结点信息和区间加值不同
Change[temp] = value;
book[temp] = true;
Tree[temp] = value*(right-left+1);
return;
}
if(book[temp])Pushdown(temp,left,right);
int mid = left + (right-left)/2;
if(ql<=mid)Updata(temp<<1,left,mid,ql,qr,value);
if(qr>mid)Updata(temp<<1|1,mid+1,right,ql,qr,value);
Tree[temp] = Tree[temp<<1]+Tree[temp<<1|1];
}
long long query(int temp,int left,int right,int ql,int qr){
if(ql<=left && qr>=right)return Tree[temp];
if(book[temp])Pushdown(temp,left,right);
int mid = left + (right-left)/2;
long long ans = 0;
if(ql<=mid)ans += query(temp<<1,left,mid,ql,qr);
if(qr>mid)ans += query(temp<<1|1,mid+1,right,ql,qr);
return ans;
}
区间合并:
const int MAXN = 100005;
int Data[MAXN];
int Change[MAXN*4];
struct D{
int l;//从左边界点开始的最大连续
int r;//从右边界点开始的最大连续
int maxn;//区间的最大连续(端点是左或右或左右边界点或没有)
int s;//区间的长度。
}Tree[MAXN*4];
void Up(int temp){
Tree[temp].l = Tree[temp<<1].l;
if(Tree[temp<<1].l == Tree[temp<<1].s)Tree[temp].l += Tree[temp<<1|1].l;
Tree[temp].r = Tree[temp<<1|1].r;
if(Tree[temp<<1|1].r == Tree[temp<<1|1].s)Tree[temp].r += Tree[temp<<1].r;
Tree[temp].maxn = max(Tree[temp<<1].maxn,Tree[temp<<1|1].maxn);
Tree[temp].maxn = max(Tree[temp].maxn,Tree[temp<<1].r+Tree[temp<<1|1].l);
}
void Build(int temp,int left,int right){
Tree[temp].s = right-left+1;
if(left == right){
if(Data[left]){ /*这里一般是两种状态,具体根据题来改*/
Tree[temp].l = Tree[temp].r = Tree[temp].maxn = 1;
}else {
Tree[temp].l = Tree[temp].r = Tree[temp].maxn = 0;
}
return ;
}
int mid = left + (right-left)/2;
Build(temp<<1,left,mid);
Build(temp<<1|1,mid+1,right);
Up(temp);
}
void PushDown(int temp){
if(Change[temp]){
/*根据题要求写*/
}
}
void Updata(int temp,int left,int right,int ql,int qr){
if(ql<=left && qr>=right){
/*根据题要求写*/
return ;
}
PushDown(temp);
int mid = left + (right-left)/2;
if(ql<=mid)Updata(temp<<1,left,mid,ql,qr);
if(qr>mid)Updata(temp<<1|1,mid+1,right,ql,qr);
Up(temp);
}
int query(int temp,int left,int right,int ql,int qr){
if(ql==left && qr==right)return Tree[temp].maxn;
PushDown(temp);
int mid = left + (right-left)/2;
if(qr<=mid)return query(temp<<1,left,mid,ql,qr);
else if(ql>mid)return query(temp<<1|1,mid+1,right,ql,qr);
else {
int a,b,c;
a = query(temp<<1,left,mid,ql,mid);
b = query(temp<<1|1,mid+1,right,mid+1,qr);
c = min(mid-ql+1,Tree[temp<<1].r) + min(qr-mid,Tree[temp<<1|1].l);
return max(a,max(b,c));
}
}