洛谷 P3372 线段树模板


【分析】
splay搞yeah


【代码】

//线段树板子(splay复习) 
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
ll n,m,sz,root,k;
int ch[mxn][2],f[mxn],size[mxn];
ll key[mxn],sum[mxn],add[mxn],a[mxn];
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline int get(int x)
{
    if(ch[f[x]][1]==x) return 1;return 0;
}
inline void update(int x)
{
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
    sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+key[x];
}
inline void ADD(int x,ll ad)
{
    add[x]+=ad,key[x]+=ad;
    sum[x]+=ad*size[x];
}
inline void pushdown(int x)
{
    if(x && add[x])
    {
        if(ch[x][0]) ADD(ch[x][0],add[x]);
        if(ch[x][1]) ADD(ch[x][1],add[x]);
        add[x]=0;
    }
}
inline void rotate(int x)
{
    pushdown(x);
    int fa=f[x],fafa=f[fa],which=get(x);
    ch[fa][which]=ch[x][which^1],f[ch[fa][which]]=fa;
    ch[x][which^1]=fa,f[fa]=x;
    f[x]=fafa;
    if(fafa) ch[fafa][ch[fafa][1]==fa?1:0]=x;
    update(fa),update(x);
}
inline void splay(int x,int lastfa)
{
    for(int fa;(fa=f[x])!=lastfa;rotate(x))
      if(f[fa]!=lastfa) rotate(get(x)==get(fa)?fa:x);
    if(!lastfa) root=x;
}
inline int number(int x)
{
    int now=root;
    while(1)
    {
        pushdown(now);
        if(x<=size[ch[now][0]] && ch[now][0]) now=ch[now][0];
        else 
        {
            if(x==size[ch[now][0]]+1) return now;
            x=x-size[ch[now][0]]-1;
            now=ch[now][1];
        }
    }
}
inline int build(int fa,int l,int r)
{
    if(l>r) return 0;
    int now=++sz,mid=l+r>>1;
    f[now]=fa,key[now]=sum[now]=a[mid],size[now]=1;
    ch[now][0]=build(now,l,mid-1);
    ch[now][1]=build(now,mid+1,r);
    update(now);
    return now;
}
int main()
{
    int i,j,x,y,opt;
    scanf("%lld%lld",&n,&m);
    fo(i,2,n+1) scanf("%lld",&a[i]);
    root=build(0,1,n+2);
    fo(i,1,m)
    {
        opt=read();
        if(opt==1)
        {
            scanf("%d%d%lld",&x,&y,&k);x++,y++;
            x=number(x-1),y=number(y+1);
            splay(x,0),splay(y,x);
            ADD(ch[y][0],k);
        }
        if(opt==2)
        {
            scanf("%d%d",&x,&y);x++,y++;
            x=number(x-1),y=number(y+1);
            splay(x,0),splay(y,x);
            printf("%lld\n",sum[ch[y][0]]);
        }
    }
    return 0;
}
### Python 实现的线段树模板代码 对于洛谷平台上的题目 `P3372模板线段树 1`,可以采用如下所示的 Python 版本的线段树实现方法[^1]。 ```python class SegmentTree: def __init__(self, data): self.n = len(data) self.tree = [0] * (4 * self.n) # 初始化线段树数组大小为原数据长度四倍 self.build(1, 0, self.n - 1, data) def build(self, node, start, end, data): if start == end: self.tree[node] = data[start] else: mid = (start + end) >> 1 self.build(node << 1, start, mid, data) self.build((node << 1) + 1, mid + 1, end, data) self.push_up(node) def update(self, idx, val): self._update(1, 0, self.n - 1, idx, val) def _update(self, node, start, end, idx, val): if start == end: self.tree[node] = val else: mid = (start + end) >> 1 if start <= idx <= mid: self._update(node << 1, start, mid, idx, val) else: self._update((node << 1) + 1, mid + 1, end, idx, val) self.push_up(node) def query(self, L, R): return self._query(1, 0, self.n - 1, L, R) def _query(self, node, start, end, L, R): if R < start or end < L: return 0 # 返回一个不影响最终结果的值 elif L <= start and end <= R: return self.tree[node] mid = (start + end) >> 1 sum_left = self._query(node << 1, start, mid, L, R) sum_right = self._query((node << 1) + 1, mid + 1, end, L, R) return sum_left + sum_right def push_up(self, node): self.tree[node] = self.tree[node << 1] + self.tree[(node << 1) + 1] if __name__ == "__main__": n, m = map(int, input().split()) a = list(map(int, input().split())) seg_tree = SegmentTree(a) results = [] for _ in range(m): cmd, x, y = input().split() x = int(x) y = int(y) if cmd == 'Q': result = seg_tree.query(x-1, y-1) results.append(result) elif cmd == 'U': seg_tree.update(x-1, y) for res in results: print(res) ``` 此代码实现了基本的线段树功能,包括构建、更新以及查询操作。特别地,在初始化阶段创建了一个足够大的列表来存储所有可能被访问到的位置,并在线程中递归地建立子区间的表示形式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值