Link Cut Tree——解决动态树问题的利器

Link Cut Tree——解决动态树问题的利器

前置技能

1. splay
2.splay区间操作 (就是能完全代替线段树的内种)
此时的splay已不再是从前的那个纯洁的 splay,甚至都不是有序二叉树,而是通过中序遍历序来维持(位置、排名等)大小关系,模板题奉上
splay区间操作线段树模板题 洛谷P3372
My code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
long long a[N];
struct tree
{
    int ch[N][2],fa[N],root;
    ll data[N],sum[N],tag[N],size[N];
    void up(int x)
    {
        size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
        sum[x]=data[x]+(ch[x][0]?sum[ch[x][0]]:0)+(ch[x][1]?sum[ch[x][1]]:0);
    }
    void down(int x)
    {
        if(tag[x])
        {
            if(ch[x][0])tag[ch[x][0]]+=tag[x],data[ch[x][0]]+=tag[x],sum[ch[x][0]]+=size[ch[x][0]]*tag[x];
            if(ch[x][1])tag[ch[x][1]]+=tag[x],data[ch[x][1]]+=tag[x],sum[ch[x][1]]+=size[ch[x][1]]*tag[x];
            tag[x]=0;
        }
    }
    void build(int l,int r,int f)
    {
        if(l>r)return;
        int mid=(l+r)>>1;
        data[mid]=a[mid],size[mid]=1,tag[mid]=0,fa[mid]=f;
        if(f)ch[f][mid>f]=mid;
        build(l,mid-1,mid),build(mid+1,r,mid);
        up(mid);
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=x==ch[y][1];
        ch[y][k]=ch[x][k^1],fa[ch[x][k^1]]=y;
        ch[x][k^1]=y,fa[y]=x;
        fa[x]=z;if(z)ch[z][y==ch[z][1]]=x;
        up(y),up(x);
    }
    void splay(int x,int goal)
    {
        while(fa[x]!=goal)
        {
            int y=fa[x],z=fa[y];
            if(z!=goal)(x==ch[y][1])^(y==ch[z][1])?rotate(x):rotate(y);
            rotate(x);
        }
        if(!goal)root=x;
    }
    int K_th(int rank)
    {
        int x=root;
        while(233)
        {
            down(x);
            if(rank<=size[ch[x][0]])x=ch[x][0];
            else if(rank<=size[ch[x][0]]+1)return x;
            else rank-=size[ch[x][0]]+1,x=ch[x][1];
        }
    }
    int op(int l,int r)
    {
        splay(K_th(l),0),splay(K_th(r+2),root);
        return ch[ch[root][1]][0];
    }
}T;

int n,m;

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=2;i<=n+1;i++)scanf("%lld",&a[i]);
    T.build(1,n+2,0);T.root=(n+3)>>1;
    int d,l,r;
    ll z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&d,&l,&r);
        int x=T.op(l,r);
        if(d==1)scanf("%lld",&z),T.sum[x]+=T.size[x]*z,T.tag[x]+=z,T.data[x]+=z;
        else printf("%lld\n",T.sum[x]);
    }
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值