线段树总结

线段树必须满足区间加法
在这里插入图片描述
区间最大值与单点修改

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#define maxl 200005
using namespace std;
int n,m;
int a[maxl];
int x,y;
struct node{int l,r,maxnum;}
tree[maxl<<2];
char ch[2];
int max(int a,int b)
{
	if(a>b)
		return a;
	else
		return b;
}

void build(int k,int l,int r)
{
	tree[k].l=l;tree[k].r=r;
	if(l==r)
	{	
		tree[k].maxnum=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);build(k<<1|1,mid+1,r);
	tree[k].maxnum=max(tree[k<<1].maxnum,tree[k<<1|1].maxnum);
}
void prework()
{
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	memset(tree,0,sizeof(tree));
	build(1,1,n);
}

int query(int k,int l,int r)
{
	int maxnum;
	if(tree[k].l==l && tree[k].r==r)
		return tree[k].maxnum;
	int mid=(tree[k].l+tree[k].r)>>1;
	if(r<=mid)
		maxnum=query(k<<1,l,r);
	else
	if(l>=mid+1)
		maxnum=query(k<<1|1,l,r);
	else
		maxnum=max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
	return maxnum;
}
void change(int k,int d,int x)
{
	if(tree[k].l==tree[k].r && tree[k].r==d)
	{
		tree[k].maxnum=x;
		return;
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(d>=tree[k].l && d<=mid)
		change(k<<1,d,x);
	else
		change(k<<1|1,d,x);
	tree[k].maxnum=max(tree[k<<1].maxnum,tree[k<<1|1].maxnum);
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		memset(a,0,sizeof(a));
		memset(tree,0,sizeof(tree));
		prework(); 
		while(m--){
			scanf("%s%d%d",ch,&x,&y);
			if(ch[0]=='Q') printf("%d\n",query(1,x,y));
			if(ch[0]=='U') change(1,x,y);
		}
	}
	return 0;
}

区间查询

inline int search(int i,int l,int r){
    if(tree[i].l>=l && tree[i].r<=r)//如果这个区间被完全包括在目标区间里面,直接返回这个区间的值
        return tree[i].sum;
    if(tree[i].r<l || tree[i].l>r)  return 0;//如果这个区间和目标区间毫不相干,返回0
    int s=0;
    if(tree[i*2].r>=l)  s+=search(i*2,l,r);//如果这个区间的左儿子和目标区间又交集,那么搜索左儿子
    if(tree[i*2+1].l<=r)  s+=search(i*2+1,l,r);//如果这个区间的右儿子和目标区间又交集,那么搜索右儿子
    return s;
}

单点修改

inline void add(int i,int dis,int k){
    if(tree[i].l==tree[i].r){//如果是叶子节点,那么说明找到了
        tree[i].sum+=k;
        return ;
    }
    if(dis<=tree[i*2].r)  add(i*2,dis,k);//在哪往哪跑
    else  add(i*2+1,dis,k);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;//返回更新
    return ;
}

如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.求出某区间每一个数的和
输入格式
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k
操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

#include<iostream>
#include<cstdio>
#define MAXN 1000001
#define ll long long
using namespace std;
unsigned ll n,m,a[MAXN],ans[MAXN<<2],tag[MAXN<<2];
inline ll ls(ll x)
{
    return x<<1;
}
inline ll rs(ll x)
{
    return x<<1|1;
}
void scan()
{
    cin>>n>>m;
    for(ll i=1;i<=n;i++)
    scanf("%lld",&a[i]);
}
inline void push_up(ll p)
{
    ans[p]=ans[ls(p)]+ans[rs(p)];
}
void build(ll p,ll l,ll r)
{
    tag[p]=0;
    if(l==r){ans[p]=a[l];return ;}
    ll mid=(l+r)>>1;
    build(ls(p),l,mid);
    build(rs(p),mid+1,r);
    push_up(p);
} 
inline void f(ll p,ll l,ll r,ll k)
{
    tag[p]=tag[p]+k;
    ans[p]=ans[p]+k*(r-l+1);
}
inline void push_down(ll p,ll l,ll r)
{
    ll mid=(l+r)>>1;
    f(ls(p),l,mid,tag[p]);
    f(rs(p),mid+1,r,tag[p]);
    tag[p]=0;
}
inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k)
{
    if(nl<=l&&r<=nr)
    {
        ans[p]+=k*(r-l+1);
        tag[p]+=k;
        return ;
    }
    push_down(p,l,r);
    ll mid=(l+r)>>1;
    if(nl<=mid)update(nl,nr,l,mid,ls(p),k);
    if(nr>mid) update(nl,nr,mid+1,r,rs(p),k);
    push_up(p);
}
ll query(ll q_x,ll q_y,ll l,ll r,ll p)
{
    ll res=0;
    if(q_x<=l&&r<=q_y)return ans[p];
    ll mid=(l+r)>>1;
    push_down(p,l,r);
    if(q_x<=mid)res+=query(q_x,q_y,l,mid,ls(p));
    if(q_y>mid) res+=query(q_x,q_y,mid+1,r,rs(p));
    return res;
}
int main()
{
    ll a1,b,c,d,e,f;
    scan();
    build(1,1,n);
    while(m--)
    {
        scanf("%lld",&a1);
        switch(a1)
        {
            case 1:{
                scanf("%lld%lld%lld",&b,&c,&d);
                update(b,c,1,n,1,d);
                break;
            }
            case 2:{
                scanf("%lld%lld",&e,&f);
                printf("%lld\n",query(e,f,1,n,1));
                break;
            }
        }
    }
    return 0;
}

如题,已知一个数列,你需要进行下面三种操作:
将某区间每一个数乘上 xx
将某区间每一个数加上 xx
求出某区间每一个数的和
输入格式
第一行包含三个整数 n,m,pn,m,p,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。
接下来 mm 行每行包含若干个整数,表示一个操作,具体如下:
操作 11: 格式:1 x y k 含义:将区间 [x,y][x,y] 内每个数乘上 kk
操作 22: 格式:2 x y k 含义:将区间 [x,y][x,y] 内每个数加上 kk
操作 33: 格式:3 x y 含义:输出区间 [x,y][x,y] 内每个数的和对 pp 取模所得的结果
面对这两种操作,可以联想到线段树的一个非常好的功能就是lazytag,只计算出确实需要访问的区间的真实值,其他的保存在lazytag里面,这样可以近似O(NlogN)的运行起来。在尝试着写了只有一个lazetag的程序之后我们发现一个lazytag是不能够解决问题的,那就上两个,分别表示乘法意义上的lazytag和加法意义上的lazytag。紧接着想到pushdown操作之后我们又发现必须在向下传递lazytag的时候人为地为这两个lazytag规定一个先后顺序,排列组合一下只有两种情况:
①加法优先,即规定好segtree[root2].value=((segtree[root2].value+segtree[root].add)segtree[root].mul)%p,问题是这样的话非常不容易进行更新操作,假如改变一下add的数值,mul也要联动变成奇奇怪怪的分数小数损失精度,我们内心是很拒绝的;
②乘法优先,即规定好segtree[root
2].value=(segtree[root2].valuesegtree[root].mul+segtree[root].add*(本区间长度))%p,这样的话假如改变add的数值就只改变add,改变mul的时候把add也对应的乘一下就可以了,没有精度损失,看起来很不错。

#include <iostream>
#include <cstdio>
using namespace std;
//题目中给的p
int p;
//暂存数列的数组
long long a[100007];
//线段树结构体,v表示此时的答案,mul表示乘法意义上的lazytag,add是加法意义上的
struct node{
    long long v, mul, add;
}st[400007];
//buildtree
void bt(int root, int l, int r){
//初始化lazytag
    st[root].mul=1;
    st[root].add=0;
    if(l==r){
        st[root].v=a[l];
    }
    else{
        int m=(l+r)/2;
        bt(root*2, l, m);
        bt(root*2+1, m+1, r);
        st[root].v=st[root*2].v+st[root*2+1].v;
    }
    st[root].v%=p;
    return ;
}
//核心代码,维护lazytag
void pushdown(int root, int l, int r){
    int m=(l+r)/2;
//根据我们规定的优先度,儿子的值=此刻儿子的值*爸爸的乘法lazytag+儿子的区间长度*爸爸的加法lazytag
    st[root*2].v=(st[root*2].v*st[root].mul+st[root].add*(m-l+1))%p;
    st[root*2+1].v=(st[root*2+1].v*st[root].mul+st[root].add*(r-m))%p;
//很好维护的lazytag
    st[root*2].mul=(st[root*2].mul*st[root].mul)%p;
    st[root*2+1].mul=(st[root*2+1].mul*st[root].mul)%p;
    st[root*2].add=(st[root*2].add*st[root].mul+st[root].add)%p;
    st[root*2+1].add=(st[root*2+1].add*st[root].mul+st[root].add)%p;
//把父节点的值初始化
    st[root].mul=1;
    st[root].add=0;
    return ;
}
//update1,乘法,stdl此刻区间的左边,stdr此刻区间的右边,l给出的左边,r给出的右边
void ud1(int root, int stdl, int stdr, int l, int r, long long k){
//假如本区间和给出的区间没有交集
    if(r<stdl || stdr<l){
        return ;
    }
//假如给出的区间包含本区间
    if(l<=stdl && stdr<=r){
        st[root].v=(st[root].v*k)%p;
        st[root].mul=(st[root].mul*k)%p;
        st[root].add=(st[root].add*k)%p;
        return ;
    }
//假如给出的区间和本区间有交集,但是也有不交叉的部分
//先传递lazytag
    pushdown(root, stdl, stdr);
    int m=(stdl+stdr)/2;
    ud1(root*2, stdl, m, l, r, k);
    ud1(root*2+1, m+1, stdr, l, r, k);
    st[root].v=(st[root*2].v+st[root*2+1].v)%p;
    return ;
}
//update2,加法,和乘法同理
void ud2(int root, int stdl, int stdr, int l, int r, long long k){
    if(r<stdl || stdr<l){
        return ;
    }
    if(l<=stdl && stdr<=r){
        st[root].add=(st[root].add+k)%p;
        st[root].v=(st[root].v+k*(stdr-stdl+1))%p;
        return ;
    }
    pushdown(root, stdl, stdr);
    int m=(stdl+stdr)/2;
    ud2(root*2, stdl, m, l, r, k);
    ud2(root*2+1, m+1, stdr, l, r, k);
    st[root].v=(st[root*2].v+st[root*2+1].v)%p;
    return ;
}
//访问,和update一样
long long query(int root, int stdl, int stdr, int l, int r){
    if(r<stdl || stdr<l){
        return 0;
    }
    if(l<=stdl && stdr<=r){
        return st[root].v;
    }
    pushdown(root, stdl, stdr);
    int m=(stdl+stdr)/2;
    return (query(root*2, stdl, m, l, r)+query(root*2+1, m+1, stdr, l, r))%p;
}
int main(){
    int n, m;
    scanf("%d%d%d", &n, &m, &p);
    for(int i=1; i<=n; i++){
        scanf("%lld", &a[i]);
    }
    bt(1, 1, n);
    while(m--){
        int chk;
        scanf("%d", &chk);
        int x, y;
        long long k;
        if(chk==1){
            scanf("%d%d%lld", &x, &y, &k);
            ud1(1, 1, n, x, y, k);
        }
        else if(chk==2){
            scanf("%d%d%lld", &x, &y, &k);
            ud2(1, 1, n, x, y, k);
        }
        else{
            scanf("%d%d", &x, &y);
            printf("%lld\n", query(1, 1, n, x, y));
        }
    }
    return 0;
}

You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#pragma GCC optimize(2)
#define maxn 100050
using namespace std;
typedef long long ll;
int n,m;
int x,y,t;
long long loop; 
struct node{
	int l,r;
	ll sum;
	ll lazy;
	int length;
}tree[maxn<<2];
char ch[2];
int a[maxn];

void pushdown(int k)
{
	if(tree[k].lazy){
		tree[k<<1].sum=tree[k<<1].sum+tree[k].lazy*tree[k<<1].length;
		tree[k<<1|1].sum=tree[k<<1|1].sum+tree[k].lazy*tree[k<<1|1].length;
		tree[k<<1].lazy+=tree[k].lazy;
		tree[k<<1|1].lazy+=tree[k].lazy;
		tree[k].lazy=0;
	}
}
void pushup(int k)
{
	tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void build(int k,int l,int r)
{
	//printf("flag"); 
	tree[k].l=l;tree[k].r=r;tree[k].lazy=0;tree[k].length=r-l+1;
	if(l==r){
		tree[k].sum=a[l];
		return;
	}
		int mid=(l+r)>>1;
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		pushup(k);

}
void prework()
{
	loop=0;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	memset(tree,0,sizeof(tree));
	build(1,1,n);
}

void update(int k,int l,int r,int lazy)
{
	if(tree[k].l==l&&tree[k].r==r){
		tree[k].sum+=tree[k].length*lazy;
		tree[k].lazy+=lazy;
		return;
	}
	pushdown(k);
	int mid=(tree[k].l+tree[k].r)>>1;
	if(mid>=r){
		update(k<<1,l,r,lazy);
	}
	else if(l>mid){
		update(k<<1|1,l,r,lazy);
	}
	else{
		update(k<<1,l,mid,lazy);
		update(k<<1|1,mid+1,r,lazy);
	}
	pushup(k);
}
//ll query(int k,int l,int r)
//{
//	if(tree[k].l==tree[k].r){
//		return tree[k].sum;
//	}
//	pushdown(k);
//	int mid=(tree[k].l+tree[k].r)>>1;
//	if(r<=mid){
//		return query(k<<1,l,r);
//	}
//	else if(l>=mid+1){
//		return query(k<<1|1,l,r);
//	}
//	else{
//		return (query(k<<1,l,mid)+query(k<<1|1,mid+1,r));
//	}
////	return suml;
//}
ll query(int k,int l,int r)
{
	if(tree[k].l==l&&tree[k].r==r)
		return tree[k].sum;
	pushdown(k);
	ll res=0;
	int m=(tree[k].l+tree[k].r)/2;
	if(r<=m)
		res+=query(2*k,l,r);
	else if(l>m)
		res+=query(2*k+1,l,r);
	else
	{
		res+=query(2*k,l,m);
		res+=query(2*k+1,m+1,r);
	}
	return res;
}
int main(){
	scanf("%d%d",&n,&m);
	prework();
	for(int l1=0;l1<m;l1++){
		scanf("%s",ch);
		if(ch[0]=='Q'){
			scanf("%d%d",&x,&y);
			printf("%lld\n",query(1,x,y));
		} 
		if(ch[0]=='C'){
			scanf("%d%d%d",&x,&y,&t);
			update(1,x,y,t);
		} 
	}

	return 0;
}

第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100000+1000;
int ans;
struct node
{
    int coun;
    int left;
    int right;
}tree[2*maxn];
int father[2*maxn];// 每个点(当区间长度为0时,对应一个点)对应的结构体数组下标 
void built(int i,int left,int right)// 为区间[left,right]建立一个以i为祖先的线段树,i为数组下标,我称作结点序号 
{
    tree[i].left=left;
    tree[i].right=right;
    //tree[i].count=0;
    if(left==right)// 当区间长度为 0 时,结束递归
    {
        scanf("%d",&tree[i].coun);//读入最下层的点
        father[left]=i;// 能知道某个点对应的序号,为了更新的时候从下往上一直到顶 
        return;
    }
    built(i*2,left,(left+right)/2);// 该结点往 左孩子的方向 继续建立线段树,线段的划分是二分思想。
    built((i*2)+1,(left+right)/2+1,right);
    tree[i].coun=tree[i*2].coun+tree[(i*2)+1].coun;
}
/*
void update(int left,int right,int rt,int pos,int add)//方法一   从上往下更新
{
    if(left==right)
    {
        tree[rt].coun+=add;
        return;
    }
    int mid=(tree[rt].left+tree[rt].right)/2;
    if(pos<=mid)
        update(left,mid,rt<<1,pos,add);
    else
        update(mid+1,right,rt<<1|1,pos,add);
    tree[rt].coun=tree[rt<<1].coun+tree[rt<<1|1].coun;
}
*/
void update(int ri)//方法二  从下往上更新
{
    if(ri==1)
    return ;//找到根节点,结束递归
   int fi=ri/2;
   tree[fi].coun=tree[fi<<1].coun+tree[(fi<<1)+1].coun;
   update(ri/2);
}
void query(int left,int right,int rt,int L,int R)// i为区间的序号(对应的区间是最大范围的那个区间,也是第一个图最顶端的区间,一般初始是 1 啦)
{
    if(L<=left&&right<=R)// 找到了一个完全重合的区间 
    {
        ans+=tree[rt].coun;
        return;
    }
    int mid=(tree[rt].left+tree[rt].right)/2;
    if(R<=mid)// 左区间有涉及 
        query(left,mid,rt<<1,L,R);
    else if(L>mid)
        query(mid+1,right,rt<<1|1,L,R);
    else
    {
        query(left,mid,rt<<1,L,R);
        query(mid+1,right,rt<<1|1,L,R);
    }
}
int main()
{
    int t,n;
    scanf("%d",&t);
    int ca=1;
    while(t--)
    {
        scanf("%d",&n);
        built(1,1,n);
        //for(int i=1;i<=n;i++)
       // printf("%d ",father[i]);
        char s[20];
        int a,b;
        printf("Case %d:\n",ca++);
        while(1)
        {
            scanf("%s",s);
            if(strcmp(s,"End")==0)
            break;
            else
            scanf("%d%d",&a,&b);
            if(strcmp(s,"Query")==0)
            {
                ans=0;
                query(1,n,1,a,b);
                printf("%d\n",ans);
            }
            if(strcmp(s,"Add")==0)
            {
                int temp=father[a];
                tree[temp].coun+=b;
                update(temp);
                //update(1,n,1,a,b);
            }
            if(strcmp(s,"Sub")==0)
            {
                int temp=father[a];
                tree[temp].coun-=b;
                update(temp);
                //update(1,n,1,a,-b);
            }
        }
    }
    return 0;
}

题意:由于中国庞大的人口和站台,总是出现票的问题,现在政府需要你去开发一个新的查票系统。
一个火车只能载k个乘客,并且每个乘客仅仅只能从a->b买一张票,在任何时间每辆火车都不能载更多的乘客。一个人提前买的票将是有效的
输入:
多组测试数据,第一行测试组数,接下来的每行有两个数字a和b
输出:
每组测试数据输出三行,第一行测试组数,如果第i次查询满足题意输出从1到i,每个数字有一个空格,每组测试后有一个空行

#include<iostream>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000005;
int ans[N];
struct node
{
    int l,r,v,lazy;
}node[N<<2];    //  线段树的空间大概是数组空间的4倍;
void build(int l,int r,int numb)    //  线段树的建立;
{
    node[numb].l=l;
    node[numb].r=r;
    node[numb].v=0;
    node[numb].lazy=0;              //  用了lazy思想,提高了效率;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(l,mid,numb<<1);
    build(mid+1,r,numb<<1|1);
}
void PushUp(int numb)               //  往上往父节点方向更新数据;但是这里不是左右儿子的和,而是最大值,因为是站台人数;
{
    node[numb].v=max(node[numb<<1].v,node[numb<<1|1].v);
}
void PushDown(int numb)             //  向下往左右儿子方向更新数据;
{
    node[numb<<1].lazy+=node[numb].lazy;
    node[numb<<1|1].lazy+=node[numb].lazy;
    node[numb<<1].v+=node[numb].lazy;
    node[numb<<1|1].v+=node[numb].lazy;
    node[numb].lazy=0;              //  更新完了要清零;
}
void Insert(int l,int r,int numb)   //  插入更新数据;
{
    if(node[numb].l==l&&node[numb].r==r)    //  如果区间完全重合,则不需要再往下更新了,先保存起来,可以节约很多的时间(lazy思想)
    {
        node[numb].v+=1;
        node[numb].lazy+=1;
        return;
    }
    if(node[numb].lazy) PushDown(numb);     //  因为没有找到完全重合的区间,所以要先更新下一层区间;
    int mid=(node[numb].r+node[numb].l)>>1;
    if(l>mid) Insert(l,r,numb<<1|1);
    else if(r<=mid) Insert(l,r,numb<<1);
    else{
        Insert(l,mid,numb<<1);
        Insert(mid+1,r,numb<<1|1);
    }
    PushUp(numb);       //  最后还得往上返回,更新父节点区间;
}
int query(int l,int r,int numb)     //  查询区间l到r;
{
    if(node[numb].l==l&&node[numb].r==r){
        return node[numb].v;
    }
    if(node[numb].lazy) PushDown(numb);     //  道理同48行;
    int mid=(node[numb].r+node[numb].l)>>1;
    if(l>mid) return query(l,r,numb<<1|1);
    else if(r<=mid) return query(l,r,numb<<1);
    else{
        return max(query(l,mid,numb<<1),query(mid+1,r,numb<<1|1));  //  道理同28行;
    }
}
int main()
{
    int t,Case=1,len=0,k,m,a,b;
    scanf("%d",&t);
    while(t--){
        len=0;
        memset(ans,0,sizeof(ans));
        scanf("%d%d",&k,&m);
        build(1,1000000,1);
        for(int i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            b--;                    //  这里有一个问题,就是乘客从a上车,b下车,所以乘客在车上的区间为(a,b--);
            if(query(a,b,1)<k){     //  表示可以上车;
                ans[len++]=i+1;
                Insert(a,b,1);
            }
        }
        printf("Case %d:\n",Case++);
        for(int i=0; i<len; i++)    //  格式问题害我又WA了一次;
            printf("%d ",ans[i]);
        printf("\n\n");
    }
    return 0;
}
 

有一个钩子,被分成了n段,初始时,每段价值都为1,输入x,y,z的意思是把第x段到第y段中的每一段的价值都变成z,问:最后这个钩子的总价值。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <map>
#define MAX 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MAXN=1e5+10;
struct Node
{
    int l,r,value;
    int mid()
    {
        return (l+r)/2.0;
    }
};
Node node[MAXN<<2];
LL add[MAXN<<2];
void pushup(int i)
{
    node[i].value=node[i<<1].value+node[i<<1|1].value;
}
void Build(int l,int r,int i)
{
    node[i].l=l;
    node[i].r=r;
    node[i].value=0;
    add[i]=0;
    if(l==r)
    {
        node[i].value=1;
        return ;
    }
    int m=node[i].mid();
    Build(l,m,i<<1);
    Build(m+1,r,i<<1|1);
    pushup(i);
}
void pushdown(int i,int L)
{
    if(add[i])
    {
        add[i<<1]=add[i];
        add[i<<1|1]=add[i];
        node[i<<1].value=add[i]*(L-(L>>1));
        node[i<<1|1].value=add[i]*(L>>1);
        add[i]=0;
    }
}
void update(int l,int r,int i,int v)
{
    if(node[i].l==l&&node[i].r==r)
    {
 
        node[i].value=v*(r-l+1);
        add[i]=v;
        return ;
    }
    pushdown(i,node[i].r-node[i].l+1);
    int m=node[i].mid();
    if(r<=m)
        update(l,r,i<<1,v);
    else if(l>m)
        update(l,r,i<<1|1,v);
    else
    {
        update(l,m,i<<1,v);
        update(m+1,r,i<<1|1,v);
    }
    pushup(i);
}
//void query(int l,int r,int i)
//{
//    if(node[i].l==node[i].r)
//    {
//
//        return ;
//    }
////    pushdown(i,node[i].r-node[i].l+1);
//    int m=node[i].mid();
//    query(l,m,i<<1);
//    query(m+1,r,i<<1|1);
//}
int main()
{
    int q,n,x,y,t,z;
    cin>>t;
    for(int i=1;i<=t;i++)
    {
        scanf("%d",&n);
        Build(1,n,1);
        scanf("%d",&q);
        for(int j=1;j<=q;j++)
        {
            scanf("%d%d%d",&x,&y,&z);
            update(x,y,1,z);
        }
        printf("Case %d: The total value of the hook is %d.\n",i,node[1].value);
    }
 
    return 0;
}
发布了3 篇原创文章 · 获赞 0 · 访问量 139
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 1024 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览