线段树的一些知识及模板

初学线段树,这篇文章主要记录线段树的一些知识和一些基本操作,更新随缘,贴一个写的非常清楚博客,大家可以直接看他的,我只是想写一遍加深理解与记忆。

https://www.cnblogs.com/TheRoadToTheGold/p/6254255.html

线段树的一些基本知识:

(1)线段树是一种二叉搜索树,它从上至下逐步将一个大区间划分成一些更小的单元区间,每个区间对应线段树中的一个节点。

(2)树中的每个节点代表着一段区间[L,R],每个节点(除叶子节点)的左儿子代表的区间为[L,mid],右儿子则为[mid+1,r]。可以发现对于一个节点来说,左右儿子所代表的区间加起来正好为当前节点的区间。(mid=(l+r)/2)

(3)叶子节点的所代表的长度为1,根节点代表的区间为整个序列区间。

(4)长度范围为[1,L] 的一棵线段树的深度为log (L) + 1。

(5)设根节点是第一个节点,那么对于第i个节点来说,若其有左孩子,则左孩子编号为2*i,若其有右孩子,则右孩子编号为2*i+1。

贴一张线段树的图片:(转自百度百科)

线段树的应用:

(1)有时候我们经常会碰到一些跟区间有关的问题,而这些问题往往是建立在一个序列上,每次询问这个序列的某个区间[L,R]的某些信息,同时经常会带有修改操作,这个操作可能是区间修改,也可能是点修改。

(2)比如询问一个序列中[L,R]的最值,或者把[L,R]整体加v。

(3)我们可以将这类问题归为以下四种形式:区间询问  区间修改  点修改 点询问。

以下以求一段区间内的最大值为例:

线段树的基本操作:

(1)建树:用结构体存储每个节点基本信息:左右区间、区间内的最大值,递归建树同时维护区间最大值这个信息,递归的边界就是区间左右端点相等。为了防止越界,一般开四倍的空间。

struct node
{
	int l,r,maxnum;
};

node tree [maxl<<2];//一般开四倍空间

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

void build(int k,int l,int r)	//节点编号为k 区间为[l,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);//维护信息
}

(2)点修改:只有三种情况:(1)当前区间左右端点相等且就是要找的点,修改对应值即可。(2)要找的点在当前区间的左半部分。(递归修改左子树)(3)要找的点在当前区间的右半部分。(递归修改右子树)以上步骤完成之后,要更新一下当前节点的信息。

void change(int k,int d,int x)	//k表示编号 把d改为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);
}

(3)区间查询:(点查询的操作就不写了)可能有四种情况:(1)当前区间就是要找的区间,那么返回该区间维护的值。(2)要找的区间在当前区间的左半部分。(在左子树查询并返回)(3)要找的区间在当前区间的右半部分。(在右子树查询并返回)(4)要找的区间在左右部分都有涉及。(在左、右子树均进行查询操作之后,取最大值返回)

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;
}

(4)区间修改:以上面那个图为例,假设要把区间[1,9]的值都加上3,如果把涉及的点都修改的话,那么复杂度会很高。(这与我们原意不符 线段树本来就是为了快速查询的!)解决的办法就是给每一个节点打上一个lazy标记,暂时先不修改该节点的子节点的值,当查询或者更新需要用到该节点的子节点的时候,再把lazy标记下传,这样复杂度就降下来了。(这里求的是区间的和)

struct node
{
	ll l,r;
	ll sum;
	ll lazy;	//lazy标记
};

node tree[100000*4+5];
ll a[100005];
ll n,m;

void build(ll i,ll l,ll r)
{
	tree[i].l=l,tree[i].r=r;
	if(l==r)
	{
		tree[i].sum=a[l];
		return ;
	}
	ll mid=(l+r)>>1;
	build(i<<1,l,mid);	//左子树
	build(i<<1|1,mid+1,r);	//右子树
	tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;//区间和
}

void down(ll i)//节点i的标记下传
{
	tree[i<<1].lazy+=tree[i].lazy;	//lazy标记下传
	tree[i<<1|1].lazy+=tree[i].lazy;
	tree[i<<1].sum+=tree[i].lazy*(tree[i<<1].r-tree[i<<1].l+1);//修改值
	tree[i<<1|1].sum+=tree[i].lazy*(tree[i<<1|1].r-tree[i<<1|1].l+1);
	tree[i].lazy=0;
}

void update(ll i,ll l,ll r,ll v)//区间[l,r]均加上v
{
	if(tree[i].l==l&&tree[i].r==r)//要修改的区间就是当前区间
	{
		tree[i].sum+=(tree[i].r-tree[i].l+1)*v;//修改区间值
		tree[i].lazy+=v;	//修改lazy标记
		return ;
	}
	if(tree[i].lazy)//走到这一步说明要用到子节点了 lazy下传
		down(i);
	ll mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)//左半区间
		update(i<<1,l,r,v);
	else if(l>=mid+1)//右半区间
		update(i<<1|1,l,r,v);
	else //左右均有
	{
		update(i<<1,l,mid,v);
		update(i<<1|1,mid+1,r,v);
	}
	tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}

ll query(ll i,ll l,ll r)
{
	if(tree[i].l==l&&tree[i].r==r)//要查询的区间就是当前区间
		return tree[i].sum;
	if(tree[i].lazy)//要用到子节点 lazy下传
		down(i);
	ll mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)//左半部分
		return query(i<<1,l,r);
	else if(l>=mid+1)	//右半部分
		return query(i<<1|1,l,r);
	else //左右均有
		return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}

区间取模+区间和+单点修改模板:

例题

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
 
const int maxl=1e5;
 
struct node
{
	int l,r;
	int maxn;
	ll sum;
};
 
node tree[maxl*4+5];
int a[maxl];
int n,m;
 
void build(int i,int l,int r)//i为当前节点编号 区间为[l,r]
{
	tree[i].l=l,tree[i].r=r;
	if(l==r)//叶子节点
	{
		tree[i].maxn=a[l];
		tree[i].sum=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(i<<1,l,mid);//左子树
	build(i<<1|1,mid+1,r);//右子树
	tree[i].maxn=max(tree[i<<1].maxn,tree[i<<1|1].maxn);//维护
	tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}
 
void update(int i,int p,int c)//i为当前节点编号 把[p,p]节点的值改为c
{
	if(tree[i].l==tree[i].r&&tree[i].r==p)//叶子节点
	{
		tree[i].maxn=c;
		tree[i].sum=c;
		return ;
	}
	int mid=(tree[i].l+tree[i].r)>>1;
	if(p<=mid)//左半区间
		update(i<<1,p,c);
	else	//右半区间
		update(i<<1|1,p,c);
	tree[i].maxn=max(tree[i<<1].maxn,tree[i<<1|1].maxn);
	tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}
 
void updatemod(int i,int x,int y,int v)//区间取模
{
    if(v>tree[i].maxn)
        return ;
    if(tree[i].l==tree[i].r)
    {
        tree[i].maxn%=v;
        tree[i].sum=tree[i].maxn;
        return ;
    }
    int mid=(tree[i].l+tree[i].r)>>1;
    if(y<=mid)
        updatemod(i<<1,x,y,v);
    else if(x>mid)
        updatemod(i<<1|1,x,y,v);
    else
        updatemod(i<<1,x,mid,v),
        updatemod(i<<1|1,mid+1,y,v);
    tree[i].maxn=max(tree[i<<1].maxn,tree[i<<1|1].maxn);
    tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}
 
ll query(int i,int l,int r)
{
	if(tree[i].l==l&&tree[i].r==r)//当前区间刚好是要找的区间
		return tree[i].sum;
	int mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)//要查询的区间在左半部分
		return query(i<<1,l,r);
	else if(l>=mid+1)//要查询的区间在右半部分
		return query(i<<1|1,l,r);
	else //左右两边均有
		return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}
 
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    int op,l,r,x;
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d %d",&op,&l,&r);
        if(op==1)
            printf("%lld\n",query(1,l,r));
        else if(op==2)
        {
            scanf("%d",&x);
            updatemod(1,l,r,x);
        }
        else
            update(1,l,r);
    }
	return 0;
}

区间开根+区间求和模板:

例题

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;

struct node
{
    int l,r;
    ll sum,MAX,MIN,lazy;
};

node tree[maxn<<2];

inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')
        ch=getchar();
    if(ch=='-')
        f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')
        x=x*10+ch-48,ch=getchar();
    return x*f;
}

inline void down(int i)
{
    int l=i<<1,r=i<<1|1;
    tree[l].lazy+=tree[i].lazy;
    tree[r].lazy+=tree[i].lazy;
    tree[l].sum+=(tree[l].r-tree[l].l+1)*tree[i].lazy;
    tree[r].sum+=(tree[r].r-tree[r].l+1)*tree[i].lazy;
    tree[l].MAX+=tree[i].lazy;
    tree[l].MIN+=tree[i].lazy;
    tree[r].MAX+=tree[i].lazy;
    tree[r].MIN+=tree[i].lazy;
    tree[i].lazy=0;
}

inline void up(int i)
{
    int l=i<<1,r=i<<1|1;
    tree[i].sum=tree[l].sum+tree[r].sum;
    tree[i].MAX=max(tree[l].MAX,tree[r].MAX);
    tree[i].MIN=min(tree[l].MIN,tree[r].MIN);
}

void build(int i,int l,int r)
{
    tree[i].l=l,tree[i].r=r;
    tree[i].lazy=0;
    if(l==r)
    {
        tree[i].MAX=tree[i].MIN=tree[i].sum=read();
        return ;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    up(i);
}

ll querysum(int i,int l,int r)
{
    if(tree[i].l==l&&tree[i].r==r)
        return tree[i].sum;
    if(tree[i].lazy)
        down(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        return querysum(i<<1,l,r);
    else if(l>mid)
        return querysum(i<<1|1,l,r);
    else
        return querysum(i<<1,l,mid)+querysum(i<<1|1,mid+1,r);
}

void update1(int i,int l,int r,ll v)
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        tree[i].sum+=(r-l+1)*v;
        tree[i].MAX+=v;
        tree[i].MIN+=v;
        tree[i].lazy+=v;
        return ;
    }
    if(tree[i].lazy)
        down(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        update1(i<<1,l,r,v);
    else if(l>mid)
        update1(i<<1|1,l,r,v);
    else
        update1(i<<1,l,mid,v),
        update1(i<<1|1,mid+1,r,v);
    up(i);
}

void update2(int i,int l,int r)
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        ll a=sqrt(tree[i].MAX);
        ll b=sqrt(tree[i].MIN);
        ll v=a-tree[i].MAX;
        int flag=0;
        if(tree[i].MAX==tree[i].MIN||tree[i].MAX-a==tree[i].MIN-b)
            flag=1;
        if(flag)
        {
            tree[i].sum+=(r-l+1)*v;
            tree[i].MAX+=v;
            tree[i].MIN+=v;
            tree[i].lazy+=v;
            return ;
        }
    }
    if(tree[i].lazy)
        down(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        update2(i<<1,l,r);
    else if(l>mid)
        update2(i<<1|1,l,r);
    else
        update2(i<<1,l,mid),
        update2(i<<1|1,mid+1,r);
    up(i);
}

int main()
{
    int n,m,op,l,r;
    ll v;
    n=read(),m=read();
    build(1,1,n);
    for(int i=0;i<m;i++)
    {
        op=read(),l=read(),r=read();
        if(op==1)
        {
            v=read();
            update1(1,l,r,v);
        }
        else if(op==2)
            update2(1,l,r);
        else
            printf("%lld\n",querysum(1,l,r));
    }
    return 0;
}

维护区间方差模板:

例题

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define eps 1e-8
using namespace std;
typedef long long ll;
const int maxn=1e5+5;

struct node
{
    int l,r;
    double lazy;
    double sum[2];//sum[0] 区间和 sum[1] 区间平方和
}tree[maxn<<2];

int n,m;
double a[maxn];

int sgn(double x)
{
	if(fabs(x)<eps)
		return 0;
	if(x>0)
		return 1;
	return -1;
}

void down(int i)
{
	int l=i<<1,r=i<<1|1;
	int len1=tree[l].r-tree[l].l+1;
	int len2=tree[r].r-tree[r].l+1;
	double v=tree[i].lazy;
	tree[l].lazy+=v,tree[r].lazy+=v;
	tree[l].sum[1]+=2*v*tree[l].sum[0]+len1*v*v;
	tree[r].sum[1]+=2*v*tree[r].sum[0]+len2*v*v;
	tree[l].sum[0]+=len1*v,tree[r].sum[0]+=len2*v;
	tree[i].lazy=0;
}

void up(int i)
{
	tree[i].sum[0]=tree[i<<1].sum[0]+tree[i<<1|1].sum[0];
	tree[i].sum[1]=tree[i<<1].sum[1]+tree[i<<1|1].sum[1];
}

void build(int i,int l,int r)
{
	tree[i].l=l,tree[i].r=r;
	tree[i].lazy=0;
	if(l==r)
	{
		tree[i].sum[0]=a[l];
		tree[i].sum[1]=a[l]*a[l];
		return ;
	}
	int mid=l+r>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	up(i);
}

void update(int i,int l,int r,double v)
{
	if(tree[i].l==l&&tree[i].r==r)
	{
		tree[i].lazy+=v;
		int len=r-l+1;
		tree[i].sum[1]+=2*v*tree[i].sum[0]+len*v*v;
		tree[i].sum[0]+=len*v;
		return ;
	}
	if(sgn(tree[i].lazy))
		down(i);
	int mid=tree[i].l+tree[i].r>>1;
	if(r<=mid)
		update(i<<1,l,r,v);
	else if(l>mid)
		update(i<<1|1,l,r,v);
	else
		update(i<<1,l,mid,v),
		update(i<<1|1,mid+1,r,v);
	up(i);
}

double query1(int i,int l,int r)//查询区间和
{
	if(tree[i].l==l&&tree[i].r==r)
		return tree[i].sum[0];
	if(sgn(tree[i].lazy))
		down(i);
	int mid=tree[i].l+tree[i].r>>1;
	if(r<=mid)
		return query1(i<<1,l,r);
	else if(l>mid)
		return query1(i<<1|1,l,r);
	else
		return query1(i<<1,l,mid)+query1(i<<1|1,mid+1,r);
}

double query2(int i,int l,int r)//查询区间平方和
{
	if(tree[i].l==l&&tree[i].r==r)
		return tree[i].sum[1];
	if(sgn(tree[i].lazy))
		down(i);
	int mid=tree[i].l+tree[i].r>>1;
	if(r<=mid)
		return query2(i<<1,l,r);
	else if(l>mid)
		return query2(i<<1|1,l,r);
	else
		return query2(i<<1,l,mid)+query2(i<<1|1,mid+1,r);
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%lf",&a[i]);
	build(1,1,n);
	int op,l,r;
	double v;
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%d",&op,&l,&r);
		if(op==1)
		{
			scanf("%lf",&v);
			update(1,l,r,v);
		}
		else if(op==2)
			printf("%.4f\n",query1(1,l,r)/(r-l+1));
		else
		{
			double tmp1=query1(1,l,r)/(r-l+1);
			double tmp2=query2(1,l,r)/(r-l+1);
			tmp1*=tmp1;
			printf("%.4f\n",tmp2-tmp1);
		}
	}
	return 0;
}

线段树维护最大连续子段和模板:(支持单点修改)

例题

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

const int maxn=5e4+5;

struct node
{
    int l,r,sum,begl,begr,ans;
}tree[maxn<<2];

int n,m;

inline void up(int i)
{
    int l=i<<1,r=i<<1|1;
    tree[i].sum=tree[l].sum+tree[r].sum;
    tree[i].begl=max(tree[l].begl,tree[l].sum+tree[r].begl);
    tree[i].begr=max(tree[r].begr,tree[r].sum+tree[l].begr);
    tree[i].ans=max(tree[l].begr+tree[r].begl,max(tree[l].ans,tree[r].ans));
}

inline void build(int i,int l,int r)
{
    tree[i].l=l,tree[i].r=r;
    if(l==r)
    {
        scanf("%d",&tree[i].sum);
        tree[i].ans=tree[i].begl=tree[i].begr=tree[i].sum;
        return ;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    up(i);
}

void update(int i,int p,int v)
{
    if(tree[i].l==tree[i].r)
    {
        tree[i].ans=tree[i].sum=tree[i].begl=tree[i].begr=v;
        return ;
    }
    int mid=(tree[i].l+tree[i].r)>>1;
    if(p<=mid)
        update(i<<1,p,v);
    else
        update(i<<1|1,p,v);
    up(i);
}

node query(int i,int l,int r)
{
    if(l==tree[i].l&&r==tree[i].r)
        return tree[i];
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        return query(i<<1,l,r);
    else if(l>mid)
        return query(i<<1|1,l,r);
    else
    {
        node lc=query(i<<1,l,mid);
        node rc=query(i<<1|1,mid+1,r);
        node tmp;
        tmp.sum=lc.sum+rc.sum;
        tmp.begl=max(lc.begl,lc.sum+rc.begl);
        tmp.begr=max(rc.begr,rc.sum+lc.begr);
        tmp.ans=max(lc.begr+rc.begl,max(lc.ans,rc.ans));
        return tmp;
    }
}

inline void prework()
{
    scanf("%d",&n);
    build(1,1,n);
}

inline void mainwork()
{
    scanf("%d",&m);
    int op,u,v;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&op,&u,&v);
        if(!op)
            update(1,u,v);
        else
            printf("%d\n",query(1,u,v).ans);
    }
}

int main()
{
    prework();
    mainwork();
    return 0;
}

线段树维护区间GCD 支持区间修改模板:

例题

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;

const int maxn=5e5+5;

struct node
{
	int l,r;
	ll v;
}tree[maxn<<2];

int n,m;
ll a[maxn];
ll dis[maxn];
ll bit[maxn];

inline ll lowbit(ll x)
{
	return x&(-x);
}

inline void add(int pos,ll v)
{
	for(int i=pos;i<=n;i+=lowbit(i))
		bit[i]+=v;
}

inline ll sum(int pos)
{
	ll ans=0;
	for(int i=pos;i;i-=lowbit(i))
		ans+=bit[i];
	return ans;
}

ll gcd(ll a,ll b)
{
	return b==0?a:gcd(b,a%b);
}

inline void up(int i)
{
	tree[i].v=gcd(tree[i<<1].v,tree[i<<1|1].v);
}

void build(int i,int l,int r)
{
	tree[i].l=l,tree[i].r=r;
	if(l==r)
	{
		tree[i].v=dis[l];
		return;
	}
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	up(i);
}

void update(int i,int pos,ll v)
{
	if(tree[i].l==tree[i].r)
	{
		tree[i].v+=v;
		return;
	}
	int mid=(tree[i].l+tree[i].r)>>1;
	if(pos<=mid)
		update(i<<1,pos,v);
	else
		update(i<<1|1,pos,v);
	up(i);
}

ll query(int i,int l,int r)
{
	if(tree[i].l==l&&tree[i].r==r)
		return tree[i].v;
	int mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)
		return query(i<<1,l,r);
	else if(l>mid)
		return query(i<<1|1,l,r);
	else
		return gcd(query(i<<1,l,mid),query(i<<1|1,mid+1,r));
}

inline void prework()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]),dis[i]=a[i]-a[i-1];
	for(int i=1;i<=n;i++)
		add(i,dis[i]);
	build(1,1,n);
}

inline void mainwork()
{
	char op[10];
	int l,r;
	ll d;
	for(int i=0;i<m;i++)
	{
		scanf("%s%d%d",op,&l,&r);
		if(op[0]=='C')
		{
			scanf("%lld",&d);
			add(l,d);
			add(r+1,-d);
			update(1,l,d);
			if(r+1<=n)
				update(1,r+1,-d);
		}
		else
			printf("%lld\n",l==r?sum(l):abs(gcd(sum(l),query(1,l+1,r))));
	}
}

int main()
{
	prework();
	mainwork();
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值