嘘~ 正在从服务器偷取页面 . . .

OI模板-数据结构


OI模板-数据结构

笛卡尔树

笛卡尔树满足

  1. 每个节点的编号满足二叉搜索树的性质。
  2. 节点 \(i\) 的权值为 \(p_i\),每个节点的权值满足小根堆的性质。

构建的复杂度为 \(\mathcal{O}(n)\)

// 2024年06月13日 22:24:45
#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
typedef long long ll;
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
#define N ((int)(1e7 + 15))

int n, top, a[N], ls[N], rs[N], stk[N];
void build()
{
    for(int i = 1; i <= n; i++)
    {
        int tmp = top;
        while(top > 0 && a[stk[top]] > a[i]) --top;
        if(top > 0) rs[stk[top]] = i; // a[stk[top]] <= a[i]
        if(top < tmp) ls[i] = stk[top + 1]; // a[stk[top + 1]] > a[i]
        stk[++top] = i;
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    build(); ll res1 = 0, res2 = 0;
    for(int i = 1; i <= n; i++)
    {
        res1 ^= (ll)i * (ls[i] + 1);
        res2 ^= (ll)i * (rs[i] + 1);
    }
    cout << res1 << ' ' << res2 << '\n';
    return 0;
}

并查集

@Roundgod老师说

按秩合并+路径压缩才能保证并查集查询的复杂度为 \(O(\alpha(n))\)

只用一个就是 \(O(\log n)\) 的,不过要特意构造数据卡才会到这个上界

基于子树大小的按秩合并:

void init(int n){for(int i=1; i<=n; i++) f[i]=i,sz[i]=1;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void merge(int u,int v)
{
    int x=find(u),y=find(v);
    if(sz[x] > sz[y]) swap(x,y);
    f[x]=y; sz[y] += sz[x];
}

基于深度的按秩合并:

int f[N],r[N]; // r[] 为深度
void init(int n){for(int i=1; i<=n; i++) f[i]=i,r[i]=0;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void merge(int x,int y)
{
    x=find(x); y=find(y);
    if(x==y) return;
    if(r[x]<r[y]) f[x]=y;
    else f[y]=x,r[x]+=r[x]==r[y];
}

种类并查集

P2024 食物链

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(5e4+15)

int n,Q,f[N<<2];
void init(int n){for(int i=1; i<=n; i++) f[i]=i;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void merge(int u,int v){f[find(u)]=find(v);}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> Q;
    int res=0; init(3*n);
    for(int op,x,y; Q--;)
    {
        cin >> op >> x >> y;
        if(x>n||y>n){++res; continue;}
        if(op==1)
        {
            if(find(x)==find(y+n)||find(x)==find(y+2*n)){++res; continue;}
            merge(x,y); merge(x+n,y+n); merge(x+2*n,y+2*n);
        }else
        {
            if(find(x)==find(y)||find(x)==find(y+n)){++res; continue;}
            merge(x,y+2*n); merge(x+n,y); merge(x+2*n,y+n);
        }
    }
    cout << res << '\n';
    return 0;
}

带权并查集

洛谷P1196 [NOI2002] 银河英雄传说 题解

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(5e5+15)

char op;
int n,f[N],sz[N],d[N];
void init(int n)
{
    for(int i=1; i<=n; i++)
        f[i]=i, sz[i]=1, d[i]=0;
}
int find(int x)
{
    if(f[x] == x)return x;
    int top = find(f[x]);
    d[x] += d[f[x]]; sz[x] = sz[top];
    return f[x]=top;
}
void merge(int u,int v)
{
    u=find(u); v=find(v);
    f[u] = v; d[u] += sz[v];
    sz[u] = sz[v] += sz[u];
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n; init(n);
    for(int i=1,x,y; i<=n; i++)
    {
        cin >> op >> x >> y;
        if(op=='M') merge(x,y);
        else
        {
            if(find(x)!=find(y))cout << "-1\n";
            else cout << abs(d[x]-d[y])-1 << '\n';
        }
    }
    return 0;
}

线性基

板子题:LOJ113 最大异或和 | LOJ114 k 大异或和

未经过严格检查的代码

最大值1个log,k大值2个log

时间复杂度 \(O((n+q)\log^2 a_i)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(66))
const int mx = 51;

int n,ck,a[N],tmp[N],o[N];
void insert(int x)
{
    for(int i=mx; i>=0; i--)
        if((x >> i) & 1)
        {
            if(!a[i]) { a[i]=x; return; }
            else x ^= a[i];
        }
    ck=1;
}
int qmax(int res=0)
{
    for(int i=mx; i>=0; i--) up(res, res^a[i]);
    return res;
}
int qmin()
{
    if(ck) return 0;
    for(int i=0; i<=mx; i++)
        if(a[i]) return a[i];
    return INF;
}
int kth(int k)
{
    int res=0, cnt=0;
    k-=ck; if(!k) return 0;
    for(int i=0; i<=mx; i++)
    {
        for(int j=i-1; j>=0; j--)
            if((a[i] >> j) & 1) a[i] ^= a[j];
        if(a[i]) o[cnt++]=a[i];
    }
    if(k >= (1ll << cnt)) return -1;
    for(int i=0; i<cnt; i++) if((k >> i) & 1) res ^= o[i];
    return res;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i=1,x; i<=n; i++) cin >> x, insert(x);
    int Q,k; cin >> Q; while(Q--) cin >> k, cout << kth(k) << '\n';
    return 0;
}

单调队列

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

手写版本(20220514)

队列用的 (l,r] 写法

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(1e6+15)

int n,k,a[N],st,en,q[N];
void solve(int n,int len,int f)
{
    st=en=0;
    for(int i=1; i<=n; i++)
    {
        if(f==1)while(st<en&&a[i]<a[q[en]])--en;
        if(f==2)while(st<en&&a[i]>a[q[en]])--en;
        q[++en]=i;
        while(st<en&&q[st+1]+len<=i)++st;
        if(i>=len)write(a[q[st+1]]),pc(" \n"[i==n]);
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    read(n);read(k);
    for(int i=1; i<=n; i++)
        read(a[i]);
    solve(n,k,1); // min
    solve(n,k,2); // max
    return 0;
}

stl版本(20211022)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() getchar()
#define pc(a) putchar(a)
#define MAXN (int)(1e6+5)
template<typename T>inline void read(T &k)
{char ch=gc();T x=0,f=1;while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}k=x*f;}
template<typename T>inline void write(T k)
{if(k<0){k=-k;pc('-');}if(k>9)write(k/10);pc(k%10+'0');}

struct node
{
    int id,num; // 下标,数
};
int n,k;
int a[MAXN];
deque<node> q1,q2;

signed main()
{
    read(n);read(k);
    for(int i=1; i<=n; i++)
        read(a[i]);
    for(int i=1; i<=n; i++) // min
    {
        while(!q1.empty()&&a[i]<q1.back().num)q1.pop_back();
        q1.push_back({i,a[i]});
        while(!q1.empty()&&q1.front().id<=i-k)q1.pop_front();
        if(i>=k){write(q1.front().num);pc(" \n"[i==n]);}
    }
    for(int i=1; i<=n; i++) // max
    {
        while(!q2.empty()&&a[i]>q2.back().num)q2.pop_back();
        q2.push_back({i,a[i]});
        while(!q2.empty()&&q2.front().id<=i-k)q2.pop_front();
        if(i>=k){write(q2.front().num);pc(" \n"[i==n]);}
    }
    return 0;
}

二叉堆

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(m^2)\)

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
// #define int long long
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(2e6+15)
int n,d[N],pos;
void push(int x)
{
	for(int f=x>>1;f>0&&d[f]>d[x];swap(d[f],d[x]),x=f,f>>=1);
}
void pop(int x)
{
	for(int s=x<<1; s<=pos;)
	{
		if(s<pos&&d[s]>d[s|1])s|=1; // 左右中最大的
		if(d[x]>d[s])swap(d[x],d[s]),x=s,s<<=1; // 去掉中间的
		else break;
	}
}
signed main()
{
	read(n);
	for(int i=1; i<=n; i++)
	{
		int op,x;read(op);
		if(op==1){read(x);d[++pos]=x;push(pos);}
		if(op==2){write(d[1]);pc('\n');}
		if(op==3){swap(d[1],d[pos]);--pos;pop(1);}
	}
	return 0;
}

左偏树(可并堆)

时间复杂度 \(O(n\log n)\)

写法1

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
char buf1[SIZ],*p1=buf1,*p2=buf1;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(1e5+15)
int n,m;
int ls[N],rs[N],del[N],dist[N],rt[N];
struct node
{
    int num,id;
    bool operator<(node &o)const
    {
        if(num==o.num)return id<o.id;
        return num<o.num;
    }
}v[N];
int merge(int x,int y)
{
    if(!x||!y)return x|y;
    if(v[y]<v[x])swap(x,y);
    rs[x]=merge(rs[x],y);
    if(dist[rs[x]]>dist[ls[x]])swap(ls[x],rs[x]);
    dist[x]=dist[rs[x]]+1;
    return x;
}
int find(int x){return rt[x]==x?x:rt[x]=find(rt[x]);}
signed main()
{
    read(n);read(m);
    for(int i=1; i<=n; i++)
    {
        read(v[i].num);
        v[i].id=i;rt[i]=i;
    }
    while(m--)
    {
        int op,x,y;
        read(op);read(x);
        if(op==1)
        {
            read(y);
            if(del[x]||del[y])continue;
            x=find(x);y=find(y);
            if(x!=y)rt[x]=rt[y]=merge(x,y);
        }else
        {
            if(del[x]){puts("-1");continue;}
            x=find(x);del[x]=1;
            write(v[x].num);pc('\n');
            rt[ls[x]]=rt[rs[x]]=rt[x]=merge(ls[x],rs[x]);
            ls[x]=rs[x]=dist[x]=0; // 这句可以不写,这样最多就安全一点(?
        }
    }
    return 0;
}

写法2(封装)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
char buf1[SIZ],*p1=buf1,*p2=buf1;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(1e5+15)
#define ls(at) t[at].ch[0]
#define rs(at) t[at].ch[1]
int n,m;
struct node
{
    int ch[2],num,id,del,dist,rt;
    bool operator<(node &o)const
    {
        if(num==o.num)return id<o.id;
        return num<o.num;
    }
}t[N];
int merge(int x,int y)
{
    if(!x||!y)return x|y;
    if(t[y]<t[x])swap(x,y);
    rs(x)=merge(rs(x),y);
    if(t[rs(x)].dist>t[ls(x)].dist)swap(ls(x),rs(x));
    t[x].dist=t[rs(x)].dist+1;
    return x;
}
int find(int x)
{
    return t[x].rt==x?x:t[x].rt=find(t[x].rt);
}
signed main()
{
    read(n);read(m);
    for(int i=1; i<=n; i++)
    {
        read(t[i].num);
        t[i].id=i;t[i].rt=i;
    }
    while(m--)
    {
        int op,x,y;
        read(op);read(x);
        if(op==1)
        {
            read(y);
            if(t[x].del||t[y].del)continue;
            x=find(x);y=find(y);
            if(x!=y)t[x].rt=t[y].rt=merge(x,y);
        }else
        {
            if(t[x].del){puts("-1");continue;}
            x=find(x);t[x].del=1;
            write(t[x].num);pc('\n');
            t[ls(x)].rt=t[rs(x)].rt=t[x].rt=merge(ls(x),rs(x));
        }
    }
    return 0;
}

珂朵莉树

CF896C Willem, Chtholly and Seniorious

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define R register
#define mod (int)(1e9+7)
#define MAXN (int)(1e5+5)
int n,m,seed,vmax;
int qpow(R int a,R int b,R int p)
{
	R int ans=1,base=a;
	while(b)
	{
		if(b&1)ans=(ans%p*base%p)%p;
		base=(base%p*base%p)%p;
		b>>=1;
	}
	return ans%p;
}
struct node
{
	int l,r;
	mutable int v;
	const bool operator<(const node &o)const
	{
		return l<o.l;
	}
};
int rnd()
{
	R int ret=seed;
	seed=(seed*7+13)%mod;
	return ret;
}
int a[MAXN];
set<node> s;
set<node>::iterator split(R int pos)
{
	set<node>::iterator it=s.lower_bound({pos});
	if(it!=s.end()&&it->l==pos) return it;
	it--;
	if(it->r<pos)return s.end();
	R int l=it->l,r=it->r,v=it->v;
	s.erase(it);
	s.insert({l,pos-1,v});
	return s.insert({pos,r,v}).first;
}
inline void add(R int l,R int r,R int k)
{
	set<node>::iterator itr=split(r+1),itl=split(l);
	for(R set<node>::iterator it=itl; it!=itr; it++)
		it->v+=k;
}
inline void assign(R int l,R int r,R int k)
{
	set<node>::iterator itr=split(r+1),itl=split(l);
	s.erase(itl,itr);//[itl,itr)
	s.insert({l,r,k});
}
struct Rank
{
	int num,cnt;
	const bool operator<(const Rank &o)const
	{
		return num<o.num;
	}
};
inline int rnk(R int l,R int r,R int k)
{
	set<node>::iterator itr=split(r+1),itl=split(l);
	vector<Rank> v;
	for(R set<node>::iterator it=itl; it!=itr; it++)
		v.push_back({it->v,it->r - it->l +1});
	sort(v.begin(),v.end());
	for(R int i=0; i<v.size(); i++)
		if(v[i].cnt<k)k-=v[i].cnt;
		else return v[i].num;
	return -1;
}
inline int calP(R int l,R int r,R int x,R int y)
{
	R int ans=0;
	set<node>::iterator itr=split(r+1),itl=split(l);
	for(set<node>::iterator it=itl; it!=itr; it++)
		ans=(ans%y+qpow(it->v,x,y)%y*(it->r - it->l +1)%y)%y;
	return ans;
}
signed main()
{
	scanf("%lld%lld%lld%lld",&n,&m,&seed,&vmax);
	for(R int i=1; i<=n; i++)
	{
		a[i]=(rnd()%vmax)+1;
		s.insert({i,i,a[i]});
	}
	for(R int i=1; i<=m; i++)
	{
		R int op,l,r,x,y;
		///
			op=(rnd()%4)+1;
			l=(rnd()%n)+1;
			r=(rnd()%n)+1;
			if(l>r)swap(l,r);
			if(op==3){x=(rnd()%(r-l+1))+1;}
			else {x=(rnd()%vmax)+1;}
			if(op==4){y=(rnd()%vmax)+1;}
		///
		if(op==1)
			add(l,r,x);
		else if(op==2)
			assign(l,r,x);
		else if(op==3)
			printf("%lld\n",rnk(l,r,x));
		else printf("%lld\n",calP(l,r,x,y));
	}
	return 0;
}

平衡树

FHQ_Treap

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(n)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e5+15)
#define gc() getchar()
#define pc(a) putchar(a)
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    if(k>9)write(k/10);
    pc(k%10+'0');
}
int n;
namespace FHQ_Treap
{
    struct node
    {
        int ch[2],num,rnd,sz;
    }t[N];
    int tot,rt;
    mt19937_64 rd(time(0));
    #define ls(x) t[x].ch[0]
    #define rs(x) t[x].ch[1]
    void push_up(int x)
    {
        t[x].sz=t[ls(x)].sz+t[rs(x)].sz+1;
    }
    int New(int x)
    {
        t[++tot]={0,0,x,(int)rd(),1};
        return tot;
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x|y;
        if(t[x].rnd<t[y].rnd)
        {
            rs(x)=merge(rs(x),y);
            push_up(x);return x;
        }else
        {
            ls(y)=merge(x,ls(y));
            push_up(y);return y;
        }
    }
    void split(int at,int k,int &x,int &y)
    {
        if(!at)x=y=0;
        else
        {
            if(t[at].num<=k)
                x=at,split(rs(at),k,rs(at),y);
            else
                y=at,split(ls(at),k,x,ls(at));
            push_up(at);
        }
    }
    int kth(int at,int x)
    {
        while(1)
        {
            if(x<=t[ls(at)].sz)
                at=ls(at);
            else if(x==t[ls(at)].sz+1)
                return at;
            else
            {
                x-=t[ls(at)].sz+1;
                at=rs(at);
            }
        }
    }
    void insert(int a)
    {
        int x,y;
        split(rt,a,x,y);
        rt=merge(merge(x,New(a)),y);
    }
    void remove(int a)
    {
        int x,y,z;
        split(rt,a,x,z);
        split(x,a-1,x,y);
        y=merge(ls(y),rs(y));
        rt=merge(merge(x,y),z);
    }
    void getrank(int a)
    {
        int x,y;
        split(rt,a-1,x,y);
        write(t[x].sz+1);pc('\n');
        rt=merge(x,y);
    }
    void getkth(int a)
    {
        write(t[kth(rt,a)].num);
        pc('\n');
    }
    void getpre(int a)
    {
        int x,y;
        split(rt,a-1,x,y);
        if(!x)write(-INF);
        else write(t[kth(x,t[x].sz)].num);
        pc('\n');rt=merge(x,y);
    }
    void getnext(int a)
    {
        int x,y;
        split(rt,a,x,y);
        if(!y)write(INF);
        else write(t[kth(y,1)].num);
        pc('\n');rt=merge(x,y);
    }
}
signed main()
{
    using namespace FHQ_Treap;
    read(n);
    for(int i=1,op,a; i<=n; i++)
    {
        read(op);read(a);
        if(op==1){insert(a);}
        if(op==2){remove(a);}
        if(op==3){getrank(a);}
        if(op==4){getkth(a);}
        if(op==5){getpre(a);}
        if(op==6){getnext(a);}
    }
}

替罪羊树

小常数还好写

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(n)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
char buf1[SIZ],*p1=buf1,*p2=buf1;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
namespace BT
{
    #define N (int)(1e5+15)
    struct node
    {
        int ch[2],num,cnt,s,sz,sd;
    }t[N];
    #define ls(x) t[x].ch[0]
    #define rs(x) t[x].ch[1]
    double alpha=0.7;
    int tot,rt;
    int tmp[N];
    int New(int x)
    {
        t[++tot]={0,0,x,1,1,1,1};
        return tot;
    }
    void push_up(int at)
    {
        t[at].s=t[ls(at)].s+t[rs(at)].s+1;
        t[at].sz=t[ls(at)].sz+t[rs(at)].sz+t[at].cnt;
        t[at].sd=t[ls(at)].sd+t[rs(at)].sd+(t[at].cnt!=0);
    }
    bool CanR(int at)
    {
        double x=t[at].s*alpha;
        return (t[at].cnt)&&(x<=(double)max(t[ls(at)].s,t[rs(at)].s)||
        (double)t[at].sd<=x);
    }
    void CanR_flatten(int &idx,int at)
    {
        if(!at)return;
        CanR_flatten(idx,ls(at));
        if(t[at].cnt)tmp[++idx]=at;
        CanR_flatten(idx,rs(at));
    }
    int CanR_build(int l,int r)
    {
        if(l>=r)return 0;
        int mid=(l+r)>>1;
        int &at=tmp[mid];
        ls(at)=CanR_build(l,mid);
        rs(at)=CanR_build(mid+1,r);
        push_up(at);
        return at;
    }
    void rebuild(int &at)
    {
        int idx=0;
        CanR_flatten(idx,at);
        at=CanR_build(1,idx+1);
    }
    void insert(int x,int &at)
    {
        if(!at){at=New(x);return;}
        if(t[at].num==x)++t[at].cnt;
        else if(x<t[at].num)insert(x,ls(at));
        else insert(x,rs(at));
        push_up(at);
        if(CanR(at))rebuild(at);
    }
    void remove(int x,int &at)
    {
        if(!at)return;
        if(t[at].num==x)
        {
            if(t[at].cnt)--t[at].cnt;
        }else if(x<t[at].num)remove(x,ls(at));
        else remove(x,rs(at));
        push_up(at);
        if(CanR(at))rebuild(at);
    }
    int getval(int x,int at)
    {
        if(!at)return INF;
        if(x<=t[ls(at)].sz)return getval(x,ls(at));
        if(x<=t[ls(at)].sz+t[at].cnt)return t[at].num;
        else return getval(x-t[ls(at)].sz-t[at].cnt,rs(at));
    }
    int uprbd(int x,int at)
    {
        if(!at)return 1;
        if(x==t[at].num&&t[at].cnt)return t[ls(at)].sz+t[at].cnt+1;
        else if(x<t[at].num)return uprbd(x,ls(at));
        else return uprbd(x,rs(at))+t[ls(at)].sz+t[at].cnt;
    }
    int uprbd_gt(int x,int at)
    {
        if(!at)return 0;
        if(x==t[at].num&&t[at].cnt)return t[ls(at)].sz;
        else if(x<t[at].num)return uprbd_gt(x,ls(at));
        else return uprbd_gt(x,rs(at))+t[ls(at)].sz+t[at].cnt;
    }
    int getpre(int x,int at){return getval(uprbd_gt(x,at),at);}
    int getnext(int x,int at){return getval(uprbd(x,at),at);}
}
signed main()
{
	using namespace BT;
	int n;read(n);
	for(int i=1; i<=n; i++)
	{
		int op,x;
		read(op);read(x);
		if(op==1)insert(x,rt);
		if(op==2)remove(x,rt);
		if(op==3){write(uprbd_gt(x,rt)+1);pc('\n');}
		if(op==4){write(getval(x,rt));pc('\n');}
		if(op==5){write(getpre(x,rt));pc('\n');}
		if(op==6){write(getnext(x,rt));pc('\n');}
	}
	return 0;
}

Splay

大常数

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(n)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define gc() getchar()
#define pc(a) putchar(a)
#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN (int)(1e5+5)
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    if(k>9)write(k/10);
    pc(k%10+'0');
}
int n;
namespace Splay
{
    struct node
    {
        int ch[2],num,fa,cnt,sz;
    }t[MAXN];
    int tot,rt;
    int New(int x,int f)
    {
        t[++tot]={0,0,x,f,1,1};
        if(f)t[f].ch[x>t[f].num]=tot;
        return tot;
    }
    void push_up(int at)
    {
        t[at].sz=t[t[at].ch[0]].sz
        +t[t[at].ch[1]].sz+t[at].cnt;
    }
    void rotate(int x)
    {
        int y=t[x].fa;
        int z=t[y].fa;
        int k=t[y].ch[1]==x;
        t[z].ch[t[z].ch[1]==y]=x;
        t[x].fa=z;
        t[y].ch[k]=t[x].ch[k^1];
        t[t[x].ch[k^1]].fa=y;
        t[x].ch[k^1]=y;
        t[y].fa=x;
        push_up(y);
        push_up(x);
    }
    void splay(int x,int goal)
    {
        while(t[x].fa!=goal)
        {
            int y=t[x].fa;
            int z=t[y].fa;
            if(z!=goal)
            (t[y].ch[1]==x)^(t[z].ch[1]==y)?rotate(x):rotate(y);
            rotate(x);
        }
        if(!goal)rt=x;
    }
    void find(int x)
    {
        int at=rt;
        if(!at)return;
        while(t[at].ch[x>t[at].num]&&x!=t[at].num)
            at=t[at].ch[x>t[at].num];
        splay(at,0);
    }
    int get(int x,int f)
    {
        find(x);
        int at=rt;
        if(t[at].num<x&&!f)return at;
        if(t[at].num>x&&f)return at;
        at=t[at].ch[f];
        while(t[at].ch[f^1])at=t[at].ch[f^1];
        return at;
    }
    void insert(int x)
    {
        int at=rt,f=0;
        while(at&&x!=t[at].num)
            f=at,at=t[at].ch[x>t[at].num];
        if(at)++t[at].cnt;
        else at=New(x,f);
        splay(at,0);
    }
    void remove(int x)
    {
        int pre=get(x,0);
        int nxt=get(x,1);
        splay(pre,0);splay(nxt,pre);
        int &del=t[nxt].ch[0];
        if(t[del].cnt>1)
        {
            --t[del].cnt;
            splay(del,0);
        }else del=0;
    }
    int kth(int x)
    {
        int at=rt;
        if(t[at].sz<x)
            return INF;
        while(1)
        {
            int p=t[at].ch[0];
            if(x>t[p].sz+t[at].cnt)
            {
                x-=t[p].sz+t[at].cnt;
                at=t[at].ch[1];
            }else
            {
                if(x<=t[p].sz)
                    at=p;
                else return t[at].num;
            }
        }
    }
}
signed main()
{
    using namespace Splay;
    insert(-INF);
    insert(INF);
    read(n);
	for(int i=1; i<=n; i++)
	{
		int op,x;
		read(op);read(x);
		if(op==1){insert(x);}
		if(op==2){remove(x);}
		if(op==3){find(x);write(t[t[rt].ch[0]].sz);pc('\n');}
		if(op==4){write(kth(x+1));pc('\n');}
		if(op==5){write(t[get(x,0)].num);pc('\n');}
		if(op==6){write(t[get(x,1)].num);pc('\n');}
	}
    return 0;
}

文艺平衡树

采用 Splay ,支持区间翻转。其实就是在原基础上打个标记而已。

// 2024年06月08日 16:36:55
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
#define N ((int)(1e5 + 15))

int n;
namespace Splay
{
    int tot, rt; 
    #define ls(at) t[at].ch[0]
    #define rs(at) t[at].ch[1]
    struct node { int ch[2], num, fa, cnt, sz, tag; } t[N];
    int New(int x, int f)
    {
        t[++tot] = {0, 0, x, f, 1, 1, 0};
        if(f) t[f].ch[x > t[f].num] = tot;
        return tot;
    }
    void push_up(int at) {
        t[at].sz = t[ls(at)].sz + t[rs(at)].sz + t[at].cnt;
    }
    void push_down(int at)
    {
        if(t[at].tag)
        {
            if(ls(at)) t[ls(at)].tag ^= 1;
            if(rs(at)) t[rs(at)].tag ^= 1;
            t[at].tag = 0; swap(ls(at), rs(at));
        }
    }
    void rotate(int x)
    {
        int y = t[x].fa, z = t[y].fa, k = rs(y) == x;
        t[z].ch[rs(z) == y] = x; t[x].fa = z;
        t[y].ch[k] = t[x].ch[k ^ 1]; t[t[x].ch[k ^ 1]].fa = y;
        t[x].ch[k ^ 1] = y; t[y].fa = x;
        push_up(y); push_up(x);
    }
    void splay(int x, int goal)
    {
        while(t[x].fa != goal)
        {
            int y = t[x].fa, z = t[y].fa;
            push_down(z); push_down(y); push_down(x);
            if(z != goal) ((rs(y) == x) ^ (rs(z) == y)) ? rotate(x) : rotate(y);
            rotate(x);
        }
        if(!goal) rt = x;
    }
    void insert(int x)
    {
        int at = rt, f = 0;
        while(at && x != t[at].num) {
            f = at; at = t[at].ch[x > t[at].num];
        }
        if(at) ++t[at].cnt; else at = New(x, f);
        splay(at, 0);
    }
    int kth(int x)
    {
        int at = rt; if(t[at].sz < x) return INF;
        while(1)
        {
            push_down(at); int p = ls(at);
            if(x > t[p].sz + t[at].cnt)
            {
                x -= t[p].sz + t[at].cnt;
                at = t[at].ch[1];
            }else
            {
                if(x <= t[p].sz) at = p;
                else return t[at].num;
            }
        }
    }
}using namespace Splay;
void work(int l, int r)
{
    l = kth(l); r = kth(r + 2);
    splay(l, 0); splay(r, l);
    t[ls(rs(rt))].tag ^= 1;
}
void output(int at)
{
    push_down(at);
    if(ls(at)) output(ls(at));
    if(t[at].num > 1 && t[at].num < n + 2) cout << t[at].num - 1 << ' ';
    if(rs(at)) output(rs(at));
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int q; cin >> n >> q;
    for(int i = 1; i <= n + 2; i++) insert(i);
    while(q--) { int l, r; cin >> l >> r; work(l, r); }
    return output(rt), 0;
}

可持久化平衡树

采用FHQ_Treap

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(5e5+15)
#define gc() getchar()
#define pc(a) putchar(a)
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    if(k>9)write(k/10);
    pc(k%10+'0');
}
int n;
namespace FHQ_Treap
{
    struct node
    {
        int ch[2],num,rnd,sz;
    }t[N*50];
    int tot,T[N];
    mt19937_64 rd(time(0));
    #define ls(x) t[x].ch[0]
    #define rs(x) t[x].ch[1]
    void push_up(int x)
    {
        t[x].sz=t[ls(x)].sz+t[rs(x)].sz+1;
    }
    int New(int x)
    {
        t[++tot]={0,0,x,(int)rd(),1};
        return tot;
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x|y;
        if(t[x].rnd<t[y].rnd)
        {
            int p=++tot;t[p]=t[x];
            rs(p)=merge(rs(p),y);
            push_up(p);return p;
        }else
        {
            int p=++tot;t[p]=t[y];
            ls(p)=merge(x,ls(p));
            push_up(p);return p;
        }
    }
    void split(int at,int k,int &x,int &y)
    {
        if(!at)x=y=0;
        else
        {
            if(t[at].num<=k)
            {
                x=++tot;t[x]=t[at];
                split(rs(x),k,rs(x),y);
                push_up(x);
            }
            else
            {
                y=++tot;t[y]=t[at];
                split(ls(y),k,x,ls(y));
                push_up(y);
            }
        }
    }
    int kth(int at,int x)
    {
        while(1)
        {
            if(x<=t[ls(at)].sz)
                at=ls(at);
            else if(x==t[ls(at)].sz+1)
                return at;
            else
            {
                x-=t[ls(at)].sz+1;
                at=rs(at);
            }
        }
    }
    void insert(int a,int &rt)
    {
        int x,y;
        split(rt,a,x,y);
        rt=merge(merge(x,New(a)),y);
    }
    void remove(int a,int &rt)
    {
        int x,y,z;
        split(rt,a,x,z);
        split(x,a-1,x,y);
        y=merge(ls(y),rs(y));
        rt=merge(merge(x,y),z);
    }
    void getrank(int a,int &rt)
    {
        int x,y;
        split(rt,a-1,x,y);
        write(t[x].sz+1);pc('\n');
        rt=merge(x,y);
    }
    void getkth(int a,int &rt)
    {
        write(t[kth(rt,a)].num);
        pc('\n');
    }
    void getpre(int a,int &rt)
    {
        int x,y;
        split(rt,a-1,x,y);
        if(!x)write(-2147483647+1);
        else write(t[kth(x,t[x].sz)].num);
        pc('\n');rt=merge(x,y);
    }
    void getnext(int a,int &rt)
    {
        int x,y;
        split(rt,a,x,y);
        if(!y)write(2147483647-1);
        else write(t[kth(y,1)].num);
        pc('\n');rt=merge(x,y);
    }
}
signed main()
{
    using namespace FHQ_Treap;
    read(n);
    for(int i=1,op,a,now; i<=n; i++)
    {
        read(now);read(op);read(a);
        T[i]=T[now];
        if(op==1){insert(a,T[i]);}
        if(op==2){remove(a,T[i]);}
        if(op==3){getrank(a,T[i]);}
        if(op==4){getkth(a,T[i]);}
        if(op==5){getpre(a,T[i]);}
        if(op==6){getnext(a,T[i]);}
    }
}

ST表

P3865 【模板】ST 表

一定要预处理 \(\log_2 n\) !! 不然查询的复杂度是假的!

因为 log() 函数的复杂度不超过log级,但是常数大!

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(n\log n)\)

代码1:

// 2023年04月02日 14:00:16
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5 + 15))

int n,Q,lg[N],st[18][N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> Q;
    for(int i = 1; i <= n; i++) cin >> st[0][i];
    for(int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;
    for(int j = 0; 1 << (j + 1) <= n; j++)
    {
        int *f = st[j], *g = st[j + 1];
        for(int i = 1; i + (1 << j) - 1 <= n; i++)
            g[i] = max(f[i], f[i + (1 << j)]);
    }
    for(int l,r; Q--; )
    {
        cin >> l >> r; int k = lg[r - l + 1]; // 这里写 r - l 也是可以的
        cout << max(st[k][l], st[k][r - (1 << k) + 1]) << '\n';
    }
    return 0;
}

代码2:

#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(1e5+5)

int n,m,lg[N],f[N][21];
void change(int u,int x)
{
	f[u][0]=x;
	for(int i=1; u>=(1<<i); i++)
		f[u][i]=max(f[u][i-1],f[u-(1<<(i-1))][i-1]);
}
int query(int l,int r)
{
	int k=lg[r-l+1];
	return max(f[l+(1<<k)-1][k],f[r][k]);
}
signed main()
{
	read(n);read(m);
	for(int i=1,x; i<=n; i++)
	{
		read(x); change(i,x);
        lg[i]=(double)log(i)/log(2);
	}
	for(int i=1,l,r; i<=m; i++)
	{
		read(l);read(r);
		write(query(l,r));pc('\n');
	}
	return 0;
}

树链剖分

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
char buf1[SIZ];
char *p1=buf1,*p2=buf1;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(1e5+5)
struct Edge
{
	int u,v,next;
}e[N<<2];
int pos=1,n,Q,rt,p,head[N];
int id[N],idx,t[N],a[N],fa[N],son[N];
int sz[N],top[N],ans[N<<2],tag[N<<2],dep[N];
void addEdge(int u,int v)
{
	e[pos]={u,v,head[u]};
	head[u]=pos++;
}
void dfs(int u,int f,int d)
{
	fa[u]=f;
	sz[u]=1;
	dep[u]=d;
	int mx=-1;
	for(int i=head[u]; i; i=e[i].next)
	{
		int v=e[i].v;
		if(v==f)continue;
		dfs(v,u,d+1);
		sz[u]+=sz[v];
		if(sz[v]>mx)mx=sz[v],son[u]=v;
	}
}
void dfs(int u,int ftop)
{
	id[u]=++idx;
	top[u]=ftop;
	a[idx]=t[u];
	if(!son[u])return;
	dfs(son[u],ftop);
	for(int i=head[u]; i; i=e[i].next)
	{
		int v=e[i].v;
		if(v==fa[u]||v==son[u])continue;
		dfs(v,v);
	}
}
void push_up(int at)
{ans[at]=ans[at<<1]+ans[at<<1|1];}
void proc(int l,int r,int at)
{
	int u=at>>1;
	ans[at]=(ans[at]+tag[u]*(r-l+1)%p)%p;
	tag[at]=(tag[at]+tag[u])%p;
}
void push_down(int l,int r,int at)
{
	int mid=(l+r)>>1;
	proc(l,mid,at<<1);
	proc(mid+1,r,at<<1|1);
	tag[at]=0;
}
void build(int l,int r,int at)
{
	tag[at]=0;
	if(l==r){ans[at]=a[l];return;}
	int mid=(l+r)>>1;
	build(l,mid,at<<1);
	build(mid+1,r,at<<1|1);
	push_up(at);
}
void update(int nl,int nr,int l,int r,int k,int at)
{
	if(nl<=l&&r<=nr)
	{
		ans[at]=(ans[at]+k%p*(r-l+1)%p)%p;
		tag[at]=(tag[at]+k)%p;
		return;
	}
	push_down(l,r,at);
	int mid=(l+r)>>1;
	if(nl<=mid)update(nl,nr,l,mid,k,at<<1);
	if(nr>mid)update(nl,nr,mid+1,r,k,at<<1|1);
	push_up(at);
}
int query(int nl,int nr,int l,int r,int at)
{
	int res=0;
	if(nl<=l&&r<=nr)
		{return ans[at]%p;}
	int mid=(l+r)>>1;
	push_down(l,r,at);
	if(nl<=mid)res=(res+query(nl,nr,l,mid,at<<1))%p;
	if(nr>mid)res=(res+query(nl,nr,mid+1,r,at<<1|1))%p;
	return res;
}
void upRange(int x,int y,int k)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		update(id[top[x]],id[x],1,n,k,1);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	update(id[x],id[y],1,n,k,1);
}
int qRange(int x,int y)
{
	int res=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		res=(res+query(id[top[x]],id[x],1,n,1))%p;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	res=(res+query(id[x],id[y],1,n,1))%p;
	return res;
}
void upSon(int x,int k){update(id[x],id[x]+sz[x]-1,1,n,k,1);}
int qSon(int x){return query(id[x],id[x]+sz[x]-1,1,n,1)%p;}
signed main()
{
	read(n);read(Q);read(rt);read(p);
	for(int i=1; i<=n; i++)
		read(t[i]);
	for(int i=1,u,v; i<n; i++)
	{
		read(u);read(v);
		addEdge(u,v);addEdge(v,u);
	}
	dfs(rt,0,1);
	dfs(rt,rt);
	build(1,n,1);
	while(Q--)
	{
		int op,x,y,k;
		read(op);
		if(op==1)
		{
			read(x);read(y);read(k);
			upRange(x,y,k);
		}
		if(op==2)
		{
			read(x);read(y);
			write(qRange(x,y));pc('\n');
		}
		if(op==3)
		{
			read(x);read(k);
			upSon(x,k);
		}
		if(op==4)
		{
			read(x);
			write(qSon(x));pc('\n');
		}
	}
	return 0;
}

树套树

1. 位置线段树套权值平衡树

P3380 【模板】二逼平衡树(树套树)

注意二分的方向

#include <bits/stdc++.h>
using namespace std;
// #define int long long
#define INF 2147483647
// #define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(1e5+15)
int n,Q,a[N];
namespace BT
{
    struct node
    {
        int ch[2],num,cnt,s,sz,sd;
    }t[N*35];
    #define ls(x) t[x].ch[0]
    #define rs(x) t[x].ch[1]
    const double alpha=0.75;
    int tot,rt,tmp[N*35];
    int New(int x)
    {
        t[++tot]={0,0,x,1,1,1,1};
        return tot;
    }
    void push_up(int at)
    {
        t[at].s=t[ls(at)].s+t[rs(at)].s+1;
        t[at].sz=t[ls(at)].sz+t[rs(at)].sz+t[at].cnt;
        t[at].sd=t[ls(at)].sd+t[rs(at)].sd+(t[at].cnt!=0);
    }
    bool CanR(int at)
    {
        double x=t[at].s*alpha;
        return (t[at].cnt)
        &&(x<=(double)max(t[ls(at)].s,t[rs(at)].s)||(double)t[at].sd<=x);
    }
    void CanR_flatten(int &idx,int at)
    {
        if(!at)return;
        CanR_flatten(idx,ls(at));
        if(t[at].cnt)tmp[++idx]=at;
        CanR_flatten(idx,rs(at));
    }
    int CanR_build(int l,int r)
    {
        if(l>=r)return 0;
        int mid=(l+r)>>1;
        int &at=tmp[mid];
        ls(at)=CanR_build(l,mid);
        rs(at)=CanR_build(mid+1,r);
        push_up(at);
        return at;
    }
    void rebuild(int &at)
    {
        int idx=0;
        CanR_flatten(idx,at);
        at=CanR_build(1,idx+1);
    }
    void insert(int x,int &at)
    {
        if(!at){at=New(x);return;}
        if(t[at].num==x)++t[at].cnt;
        else if(x<t[at].num)insert(x,ls(at));
        else insert(x,rs(at));
        push_up(at);
        if(CanR(at))rebuild(at);
    }
    void remove(int x,int &at)
    {
        if(!at)return;
        if(t[at].num==x)
        {
            if(t[at].cnt)--t[at].cnt;
        }else if(x<t[at].num)remove(x,ls(at));
        else remove(x,rs(at));
        push_up(at);
        if(CanR(at))rebuild(at);
    }
    int getval(int x,int at)
    {
        if(!at)return INF;
        if(x<=t[ls(at)].sz)return getval(x,ls(at));
        if(x<=t[ls(at)].sz+t[at].cnt)return t[at].num;
        else return getval(x-t[ls(at)].sz-t[at].cnt,rs(at));
    }
    int uprbd(int x,int at)
    {
        if(!at)return 1;
        if(x==t[at].num&&t[at].cnt)return t[ls(at)].sz+t[at].cnt+1;
        else if(x<t[at].num)return uprbd(x,ls(at));
        else return uprbd(x,rs(at))+t[ls(at)].sz+t[at].cnt;
    }
    int uprbd_gt(int x,int at)
    {
        if(!at)return 0;
        if(x==t[at].num&&t[at].cnt)return t[ls(at)].sz;
        else if(x<t[at].num)return uprbd_gt(x,ls(at));
        else return uprbd_gt(x,rs(at))+t[ls(at)].sz+t[at].cnt;
    }
    int getpre(int x,int at)
	{
		int res=getval(uprbd_gt(x,at),at);
		return res==INF?-INF:res;
	}
	int getnext(int x,int at)
	{
		int res=getval(uprbd(x,at),at);
		return res==INF?INF:res;
	}
}
namespace SEG
{
    struct node
    {
        int l,r,rt;
    }s[N<<2];
    #define lc(at) (at<<1)
    #define rc(at) (at<<1|1)
    void build(int l,int r,int at)
    {
        s[at].l=l;s[at].r=r;
        for(int i=l; i<=r; i++)
        BT::insert(a[i],s[at].rt);
        if(l==r)return;
        int mid=(l+r)>>1;
        build(l,mid,lc(at));
        build(mid+1,r,rc(at));
    }
    void update(int pos,int k,int at)
    {
        BT::remove(a[pos],s[at].rt);
        BT::insert(k,s[at].rt);
        if(s[at].l==s[at].r)return;
        int mid=(s[at].l+s[at].r)>>1;
        if(pos<=mid)update(pos,k,lc(at));
        else update(pos,k,rc(at));
    }
    int getrank(int L,int R,int k,int at)
    {
        int l=s[at].l,r=s[at].r;
        if(l>R||r<L)return 0;
        if(L<=l&&r<=R)return BT::uprbd_gt(k,s[at].rt);
        return getrank(L,R,k,lc(at))+getrank(L,R,k,rc(at));
    }
    // a=getrank(x),b=getrank(y)
    // a=b => x=y
    // x=y =/> a=b 
    // int getkth(int L,int R,int k)
    // {
    //     int l=0,r=1e8+5;
    //     while(l<r)
    //     {
    //         int mid=(l+r)>>1;
    //         if(getrank(L,R,mid,1)+1>=k)r=mid;
    //         else l=mid+1;
    //     }
    //     return l;
    // }
    int getkth(int L,int R,int k)
    {
        int l=0,r=1e8+5;
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            if(getrank(L,R,mid,1)+1<=k)l=mid;
            else r=mid-1;
        }
        return l;
    }
    int getpre(int L,int R,int k,int at)
    {
        int l=s[at].l,r=s[at].r;
        if(l>R||r<L)return -INF;
        if(L<=l&&r<=R)
            return BT::getpre(k,s[at].rt);
        return max(getpre(L,R,k,lc(at)),getpre(L,R,k,rc(at)));
    }
    int getnext(int L,int R,int k,int at)
    {
        int l=s[at].l,r=s[at].r;
        if(l>R||r<L)return INF;
        if(L<=l&&r<=R)
            return BT::getnext(k,s[at].rt);
        return min(getnext(L,R,k,lc(at)),getnext(L,R,k,rc(at)));
    }
}
signed main()
{
    using namespace SEG;
    // ios::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);
    read(n);read(Q);
    for(int i=1; i<=n; i++)
        read(a[i]);
    build(1,n,1);
    int op,x,y,k;
    while(Q--)
    {
        read(op);read(x);read(y);
        if(op==3)
        {
            update(x,y,1);
            a[x]=y;
        }else
        {
            read(k);
            if(op==1)write(getrank(x,y,k,1)+1);
            else if(op==2)write(getkth(x,y,k));
            else if(op==4)write(getpre(x,y,k,1));
            else if(op==5)write(getnext(x,y,k,1));
            pc('\n');
        }
    }
    return 0;
}

2. 树状数组套权值线段树(带修主席树)

注意维护的是权值线段树不是可持久化权值线段树,带修和不带修类似于树状数组和前缀和数组的差异。

参考 洛谷P2617 Dynamic Rankings 题解 (懒得写模板题)

时间复杂度 \(\mathcal{O}(n \log^2 n)\) ,空间复杂度 \(\mathcal{O}(n \log ^2 n)\)

代码:(支持单点修改 + 区间第 \(k\) 大值查询)

// 2024年06月12日 18:15:58
#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
typedef long long ll;
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
#define ls(at) tr[at].ls
#define rs(at) tr[at].rs
#define N ((int)(1e5 + 15))

int n, len, tot, a[N], o[N * 2], rt[N], tmp[2][25], cnt[2];
struct node { int ls, rs, v; } tr[N * 400];
struct qry { int op, x, y, k; } q[N];
int lowbit(int x) { return x & (-x); }
void Modify(int &at, int l, int r, int x, int v)
{
    if(!at) at = ++tot;
    tr[at].v += v; if(l == r) return;
    int mid = (l + r) >> 1;
    if(x <= mid) Modify(ls(at), l, mid, x, v);
    else Modify(rs(at), mid + 1, r, x, v);
}
void pre_Modify(int x, int v)
{
    int p = lower_bound(o + 1, o + 1 + len, a[x]) - o;
    for(int i = x; i <= n; i += lowbit(i)) Modify(rt[i], 1, len, p, v);
}
int Query(int l, int r, int k)
{
    if(l == r) return l;
    int mid = (l + r) >> 1, sum = 0;
    for(int i = 1; i <= cnt[0]; i++) sum -= tr[ls(tmp[0][i])].v;
    for(int i = 1; i <= cnt[1]; i++) sum += tr[ls(tmp[1][i])].v;
    if(k <= sum)
    {
        for(int i = 1; i <= cnt[0]; i++) tmp[0][i] = ls(tmp[0][i]);
        for(int i = 1; i <= cnt[1]; i++) tmp[1][i] = ls(tmp[1][i]);
        return Query(l, mid, k);
    }else
    {
        for(int i = 1; i <= cnt[0]; i++) tmp[0][i] = rs(tmp[0][i]);
        for(int i = 1; i <= cnt[1]; i++) tmp[1][i] = rs(tmp[1][i]);
        return Query(mid + 1, r, k - sum);
    }
}
int pre_Query(int l, int r, int k)
{
    memset(tmp, 0, sizeof(tmp)); cnt[0] = cnt[1] = 0;
    for(int i = l - 1; i; i -= lowbit(i)) tmp[0][++cnt[0]] = rt[i];
    for(int i = r; i; i -= lowbit(i)) tmp[1][++cnt[1]] = rt[i];
    return Query(1, len, k);
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int m; cin >> n >> m; char op;
    for(int i = 1; i <= n; i++) { cin >> a[i]; o[++len] = a[i]; }
    for(int i = 1; i <= m; i++)
    {
        cin >> op; q[i].op = (op == 'Q') + 1;
        if(q[i].op == 2) { cin >> q[i].x >> q[i].y >> q[i].k; }
        else { cin >> q[i].x >> q[i].y; o[++len] = q[i].y; } 
    }
    sort(o + 1, o + len + 1); len = unique(o + 1, o + len + 1) - o - 1;
    for(int i = 1; i <= n; i++) pre_Modify(i, 1);
    for(int i = 1; i <= m; i++)
    {
        if(q[i].op == 1)
        {
            pre_Modify(q[i].x, -1);
            a[q[i].x] = q[i].y; pre_Modify(q[i].x, 1);
        } else { cout << o[pre_Query(q[i].x, q[i].y, q[i].k)] << '\n'; }
    }
    return 0;
}

树状数组

树状数组的具体文章详见 浅谈树状数组 区间修改&区间查询

最新的模板:(单点修改区间查询)

// 2023年06月23日 09:22:14
#define lowbit(x) ((x) & (-(x)))
void add(int x,int v) {
    for(int i = x; i && i <= tot; i += lowbit(i)) tree[i] += v;
}
int sum(int x) {
    int res = 0; for(int i = x; i; i -= lowbit(i)) res += tree[i]; return res;
}

线段树

线段树1 朴素写法

P3372 【模板】线段树 1

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
char buf1[SIZ],*p1,*p2;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(1e5+15)
int n,Q;
int a[N];
struct node
{
    int sum,tag;
}t[N<<2];
#define ls(at) (at<<1)
#define rs(at) (at<<1|1)
void push_up(int at)
{
    t[at].sum=t[ls(at)].sum+t[rs(at)].sum;
}
void build(int l,int r,int at)
{
    if(l==r)
    {
        t[at].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls(at));
    build(mid+1,r,rs(at));
    push_up(at);
}
void proc(int l,int r,int k,int at)
{
    t[at].sum+=k*(r-l+1);
    t[at].tag+=k;
}
void push_down(int l,int r,int at)
{
    if(t[at].tag)
    {
        int mid=(l+r)>>1;
        proc(l,mid,t[at].tag,ls(at));
        proc(mid+1,r,t[at].tag,rs(at));
    }
    t[at].tag=0;
}
void update(int nl,int nr,int l,int r,int k,int at)
{
    if(nl<=l&&r<=nr)
    {
        t[at].sum+=k*(r-l+1);
        t[at].tag+=k;
        return;
    }
    int mid=(l+r)>>1;
    push_down(l,r,at);
    if(nl<=mid)update(nl,nr,l,mid,k,ls(at));
    if(nr>mid)update(nl,nr,mid+1,r,k,rs(at));
    push_up(at);
}
int query(int nl,int nr,int l,int r,int at)
{
    if(nl<=l&&r<=nr)
        {return t[at].sum;}
    int mid=(l+r)>>1,res=0;
    push_down(l,r,at);
    if(nl<=mid)res+=query(nl,nr,l,mid,ls(at));
    if(nr>mid)res+=query(nl,nr,mid+1,r,rs(at));
    return res;
}
signed main()
{
    read(n);read(Q);
    for(int i=1; i<=n; i++)
        read(a[i]);
    build(1,n,1);
    while(Q--)
    {
        int op,l,r,k;
        read(op);
        if(op==1)
        {
            read(l);read(r);read(k);
            update(l,r,1,n,k,1);
        }else
        {
            read(l);read(r);
            write(query(l,r,1,n,1));pc('\n');
        }
    }
    return 0;
}

还有一种比较好的query写法,如下


int query(int nl,int nr,int l,int r,int at)
{
    if(nl<=l&&r<=nr)
        // return ...;
    if(nr<=mid)return query(nl,nr,l,mid,ls(at));
    if(nl>mid)return query(nl,nr,mid+1,r,rs(at));
    return query(nl,nr,l,mid,ls(at))+query(nl,nr,mid+1,r,rs(at));
}

线段树1 标记永久化+动态开点

P3372 【模板】线段树 1

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e6+15)
char buf1[SIZ],*p1,*p2;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(1e5+15)
struct node
{
    int ch[2],ans,tag;
}t[N<<2];
int rt,tot;
int n,Q,a[N];
#define ls(at) t[at].ch[0]
#define rs(at) t[at].ch[1]
void insert(int nl,int nr,int l,int r,int x,int &at)
{
    if(!at)at=++tot;
    t[at].ans+=x*(min(r,nr)-max(l,nl)+1);
    if(nl<=l&&r<=nr)
    {
        t[at].tag+=x;
        return;
    }
    int mid=(l+r)>>1;
    if(nl<=mid)insert(nl,nr,l,mid,x,ls(at));
    if(nr>mid)insert(nl,nr,mid+1,r,x,rs(at));
}
void pusht(int l,int r,int x,int &at)
{
    if(!at)at=++tot;
    t[at].ans+=(r-l+1)*x;
    t[at].tag+=x;
}
int query(int nl,int nr,int l,int r,int at)
{
    if(nl<=l&&r<=nr)
        return t[at].ans;
    int mid=(l+r)>>1;
    if(t[at].tag)
    {
        pusht(l,mid,t[at].tag,ls(at));
        pusht(mid+1,r,t[at].tag,rs(at));
        t[at].tag=0;
    }
    int res=0;
    if(nl<=mid)res+=query(nl,nr,l,mid,ls(at));
    if(nr>mid)res+=query(nl,nr,mid+1,r,rs(at));
    return res;
}
signed main()
{
    read(n);read(Q);
    for(int i=1; i<=n; i++)
    {
        read(a[i]);
        insert(i,i,1,n,a[i],rt);
    }
    while(Q--)
    {
        int op,l,r,x;
        read(op);read(l);read(r);
        if(op==1){read(x);insert(l,r,1,n,x,rt);}
        else write(query(l,r,1,n,rt)),pc('\n');
    }
    return 0;
}

李超线段树

P4097 [HEOI2013]Segment

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(1e5+15)
#define M (int)(4e4+15)
#define ls(at) (at<<1)
#define rs(at) (at<<1|1)
const int mod1=39989;
const int mod2=1e9;
struct line
{
    double k,b;
}li[N];
int bs[M<<2],n,lstans,cnt;
double calc(int id,int x)
{
    return li[id].k*x+li[id].b;
}
void init(int x1,int y1,int x2,int y2)
{
    ++cnt;
    if(x1==x2)
    {
        li[cnt].k=0;
        li[cnt].b=max(y1,y2);
    }else
    {
        li[cnt].k=1.0*(y1-y2)/(x1-x2);
        li[cnt].b=y1-li[cnt].k*x1;
    }
}
void update(int nl,int nr,int l,int r,int nw,int at)
{
    int u=bs[at];
    int mid=(l+r)>>1;
    double now=calc(nw,mid),resu=calc(u,mid);
    if(nl<=l&&r<=nr)
    {
        if(l==r)
        {
            if(now>resu)
                bs[at]=nw;
            return;
        }
        if(li[nw].k>li[u].k)
        {
            if(now>resu)
            {
                bs[at]=nw;
                update(nl,nr,l,mid,u,ls(at));
            }else update(nl,nr,mid+1,r,nw,rs(at));
        }else if(li[nw].k<li[u].k)
        {
            if(now>resu)
            {
                bs[at]=nw;
                update(nl,nr,mid+1,r,u,rs(at));
            }else update(nl,nr,l,mid,nw,ls(at));
        }else if(li[nw].b>li[u].b)bs[at]=nw;
        return;
    }
    if(nl<=mid)update(nl,nr,l,mid,nw,ls(at));
    if(nr>mid)update(nl,nr,mid+1,r,nw,rs(at));
}
struct node{double v;int x;};
node max(node a,node b)
{
    if(a.v==b.v)return a.x<b.x?a:b;
    return a.v>b.v?a:b;
}
node query(int l,int r,int x,int at)
{
    if(r<x||l>x)return {0,0};
    int mid=(l+r)>>1;
    node tmp={calc(bs[at],x),bs[at]};
    if(l==r)return tmp;
    return max(tmp,max(query(l,mid,x,ls(at)),query(mid+1,r,x,rs(at))));
}
#define change1(x) (x=(x+lstans-1+mod1)%mod1+1)
#define change2(x) (x=(x+lstans-1+mod2)%mod2+1)
signed main()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    read(n);
    int op,x1,y1,x2,y2;
    for(int i=1; i<=n; i++)
    {
        read(op);
        if(op==1)
        {
            read(x1);read(y1);read(x2);read(y2);
            change1(x1);change1(x2);change2(y1);change2(y2);
            if(x1>x2)swap(x1,x2),swap(y1,y2);
            init(x1,y1,x2,y2);update(x1,x2,1,M,cnt,1);
        }else
        {
            int x;read(x);change1(x);
            write(lstans=query(1,M,x,1).x);pc('\n');
        }
    }
    return 0;
}

线段树合并

P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

未经过严格验证正确性

时间复杂度 \(O(n \log n)\)

#include <bits/stdc++.h>
using namespace std;
// #define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(1e5+15)
int n,m,ans[N];
struct Edge
{
    int u,v,next;
}e[N<<1];
int pos=1,head[N];
int fa[N],son[N],sz[N],top[N],dep[N];
int val[N*70],ch[N*70][2],rt[N],tot,Z,typ[N*70];
#define ls(at) ch[at][0]
#define rs(at) ch[at][1]
void addEdge(int u,int v)
{
    e[++pos]={u,v,head[u]};
    head[u]=pos;
}
void dfs(int u,int f,int d)
{
    fa[u]=f;
    sz[u]=1;
    dep[u]=d;
    int mx=-1;
    for(int i=head[u]; i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==f)continue;
        dfs(v,u,d+1);
        sz[u]+=sz[v];
        if(sz[v]>mx)mx=sz[v],son[u]=v;
    }
}
void dfs(int u,int ftop)
{
    top[u]=ftop;
    if(!son[u])return;
    dfs(son[u],ftop);
    for(int i=head[u]; i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa[u]||v==son[u])continue;
        dfs(v,v);
    }
}
int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
void push_up(int at)
{
    if(val[ls(at)]>=val[rs(at)])
        val[at]=val[ls(at)],typ[at]=typ[ls(at)];
    else val[at]=val[rs(at)],typ[at]=typ[rs(at)];
}
void modify(int l,int r,int pos,int v,int &at)
{
    if(!at)at=++tot;
    if(l==r)
    {
        val[at]+=v;
        typ[at]=l;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)modify(l,mid,pos,v,ls(at));
    else modify(mid+1,r,pos,v,rs(at));
    push_up(at);
}
int merge(int x,int y,int l,int r)
{
    if(!x||!y)return x|y;
    if(l==r)
    {
        val[x]+=val[y];
        typ[x]=l;
        return x;
    }
    int mid=(l+r)>>1;
    ls(x)=merge(ls(x),ls(y),l,mid);
    rs(x)=merge(rs(x),rs(y),mid+1,r);
    push_up(x);
    return x;
}
void calc(int u)
{
    for(int i=head[u]; i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa[u])continue;
        calc(v);
        rt[u]=merge(rt[u],rt[v],1,Z);
    }
    if(val[rt[u]])ans[u]=typ[rt[u]];
}
int u[N],v[N],z[N];
signed main()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);
    read(n);read(m);
    for(int i=1,u,v; i<n; i++)
    {
        read(u);read(v);
        addEdge(u,v);addEdge(v,u);
    }
    dfs(1,0,1);dfs(1,1);
    for(int i=1; i<=m; i++)
        read(u[i]),read(v[i]),read(z[i]),Z=max(Z,z[i]);
    for(int i=1; i<=m; i++)
    {
        int d=lca(u[i],v[i]);
        modify(1,Z,z[i],1,rt[u[i]]);
        modify(1,Z,z[i],1,rt[v[i]]);
        modify(1,Z,z[i],-1,rt[d]);
        modify(1,Z,z[i],-1,rt[fa[d]]);
    }
    calc(1);
    for(int i=1; i<=n; i++)
        write(ans[i]),pc('\n');
    return 0;
}

线段树分裂

P5494 【模板】线段树分裂

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(2e5+15)
int n,Q,tot,rcnt,seq=1;
int bac[N*35],ch[N*35][2],rt[N],val[N*35];
int newnod(){return rcnt?bac[rcnt--]:++tot;}
#define ls(at) ch[at][0]
#define rs(at) ch[at][1]
void del(int at)
{
    bac[++rcnt]=at;
    ls(at)=rs(at)=val[at]=0;
}
void modify(int l,int r,int pos,int v,int &at)
{
    if(!at)at=newnod();
    val[at]+=v;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)modify(l,mid,pos,v,ls(at));
    else modify(mid+1,r,pos,v,rs(at));
}
int query(int nl,int nr,int l,int r,int at)
{
    if(nr<l||r<nl)return 0;
    if(nl<=l&&r<=nr)return val[at];
    int mid=(l+r)>>1;
    return query(nl,nr,l,mid,ls(at))+query(nl,nr,mid+1,r,rs(at));
}
int kth(int l,int r,int k,int at)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(k<=val[ls(at)])return kth(l,mid,k,ls(at));
    else return kth(mid+1,r,k-val[ls(at)],rs(at));
}
int merge(int x,int y)
{
    if(!x||!y)return x|y;
    val[x]+=val[y];
    ls(x)=merge(ls(x),ls(y));
    rs(x)=merge(rs(x),rs(y));
    del(y);
    return x;
}
void split(int x,int &y,int k)
{
    if(!x)return;
    y=newnod();
    int v=val[ls(x)];
    if(k>v)split(rs(x),rs(y),k-v);
    else
    {
        swap(rs(x),rs(y));
        if(k<v)split(ls(x),ls(y),k);
    }
    val[y]=val[x]-k;
    val[x]=k;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    read(n);read(Q);
    for(int i=1,x; i<=n; i++)
    {
        read(x);
        modify(1,n,i,x,rt[1]);
    }
    int op,x,y,z;
    while(Q--)
    {
        read(op);
        if(op==0)
        {
            read(x);read(y);read(z);
            int k1=query(1,z,1,n,rt[x]);
            int k2=query(y,z,1,n,rt[x]);
            int tmp=0;
            split(rt[x],rt[++seq],k1-k2);
            split(rt[seq],tmp,k2);
            rt[x]=merge(rt[x],tmp);
        }else if(op==1)
        {
            read(x);read(y);
            rt[x]=merge(rt[x],rt[y]);
        }else if(op==2)
        {
            read(x);read(y);read(z);
            modify(1,n,z,y,rt[x]);
        }else if(op==3)
        {
            read(x);read(y);read(z);
            write(query(y,z,1,n,rt[x]));pc('\n');
        }else if(op==4)
        {
            read(x);read(y);
            if(val[rt[x]]<y){puts("-1");continue;}
            write(kth(1,n,y,rt[x]));pc('\n');
        }
    }
    return 0;
}

静态仙人掌

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
char buf1[SIZ],*p1=buf1,*p2=buf1;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void print(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(4e4+15)
int n,m,Q,dfncnt,ext;
int dfn[N],low[N],fa[N],ans;
int top[N],son[N],sz[N],dep[N],b[N],sum[N],dis[N];
struct Edge
{
    int v,w;
};
vector<Edge> vec[N],exv[N];
int find(int u,int f)
{
    int res;
    while(top[u]!=top[f])
    {
        res=top[u];
        u=fa[top[u]];
    }
    return u==f?res:son[f];
}
int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
void dfs(int u,int f,int d)
{
    dep[u]=d+1;fa[u]=f;sz[u]=1;
    int mx=-1;
    for(int i=0; i<exv[u].size(); i++)
    {
        int v=exv[u][i].v;
        if(v==f)continue;
        dis[v]=dis[u]+exv[u][i].w;
        dfs(v,u,d+1);
        sz[u]+=sz[v];
        if(sz[v]>mx)mx=sz[v],son[u]=v;
    }
}
void dfs(int u,int ftop)
{
    top[u]=ftop;
    if(!son[u])return;
    dfs(son[u],ftop);
    for(int i=0; i<exv[u].size(); i++)
    {
        int v=exv[u][i].v;
        if(v==fa[u]||v==son[u])
            continue;
        dfs(v,v);
    }
}
void proc(int u,int v,int w)
{
    ++ext;
    int pw,pre=w,x=v;
    while(x!=fa[u])
    {
        sum[x]=pre;
        pre+=b[x];
        x=fa[x];
    }
    sum[ext]=sum[u];
    sum[u]=0;x=v;
    while(x!=fa[u])
    {
        pw=min(sum[x],sum[ext]-sum[x]);
        exv[ext].push_back({x,pw});
        exv[x].push_back({ext,pw});
        x=fa[x];
    }
}
void tarjan(int u,int f)
{
    dfn[u]=low[u]=++dfncnt;
    for(int i=0; i<vec[u].size(); i++)
    {
        int v=vec[u][i].v,w=vec[u][i].w;
        if(v==f)continue;
        if(!dfn[v])
        {
            fa[v]=u;b[v]=w;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }else low[u]=min(low[u],dfn[v]);
        if(low[v]>dfn[u])
        {
            exv[u].push_back({v,w});
            exv[v].push_back({u,w});
        }
    }
    for(int i=0; i<vec[u].size(); i++)
    {
        int v=vec[u][i].v;
        if(fa[v]!=u&&dfn[v]>dfn[u])
            proc(u,v,vec[u][i].w);
    }
}
signed main()
{
    read(n);read(m);read(Q);ext=n;
    for(int i=1,u,v,w; i<=m; i++)
    {
        read(u);read(v);read(w);
        vec[u].push_back({v,w});
        vec[v].push_back({u,w});
    }
    tarjan(1,0);dfs(1,0,1);dfs(1,1);
    while(Q--)
    {
        int u,v,p,A,B;read(u);read(v);
        p=lca(u,v);
        if(p<=n)ans=dis[u]+dis[v]-(dis[p]<<1);
        else
        {
            A=find(u,p);B=find(v,p);
            ans=dis[u]+dis[v]-dis[A]-dis[B];
            int tmp=abs(sum[A]-sum[B]);
            ans+=min(tmp,sum[p]-tmp);
        }
        print(ans);pc('\n');
    }
    return 0;
}

可持久化数组

  1. 主席树实现被卡了long long

时间复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+25)
char buf1[SIZ];
char *p1=buf1,*p2=buf1;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(1e6+5)
int n,Q;
int a[N],T[N],tot;
struct node
{
    int ch[2],num;
}t[N<<5];
#define ls(at) t[at].ch[0]
#define rs(at) t[at].ch[1]
int build(int l,int r)
{
    int at=++tot,mid=(l+r)>>1;
    if(l==r){t[at].num=a[l];return at;}
    ls(at)=build(l,mid);
    rs(at)=build(mid+1,r);
    return at;
}
int update(int pre,int l,int r,int x,int v)
{
    int at=++tot,mid=(l+r)>>1;
    t[at]=t[pre];
    if(l==r)
    {
        t[at].num=v;
        return at;
    }
    if(x<=mid)ls(at)=update(ls(pre),l,mid,x,v);
    else rs(at)=update(rs(pre),mid+1,r,x,v);
    return at;
}
int query(int at,int l,int r,int x)
{
    if(l==r)return t[at].num;
    int mid=(l+r)>>1;
    if(x<=mid)return query(ls(at),l,mid,x);
    else return query(rs(at),mid+1,r,x);
}
signed main()
{
    read(n);read(Q);
    for(int i=1; i<=n; i++)
        read(a[i]);
    T[0]=build(1,n);
    for(int i=1; i<=Q; i++)
    {
        int rt,op,x,y;
        read(rt);read(op);read(x);
        if(op==1)
        {
            read(y);
            T[i]=update(T[rt],1,n,x,y);
        }else
        {
            write(query(T[rt],1,n,x));
            pc('\n');T[i]=T[rt];
        }
    }
    return 0;
}
  1. Elegia神仙的神仙解法(离线解法)

    根据依赖关系,且可逆操作,建关系树,然后跑dfs

    时间复杂度 \(O(n)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+25)
char buf1[SIZ];
char *p1=buf1,*p2=buf1;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(1e6+5)
int n,Q;
int a[N],op[N],k[N],x[N],ans[N];
vector<int>vec[N];
void dfs(int u)
{
    if(op[u]==2)
    {
        ans[u]=a[k[u]];
        for(int v:vec[u])dfs(v);
    }else
    {
        swap(a[k[u]],x[u]);
        for(int v:vec[u])dfs(v);
        swap(a[k[u]],x[u]);
    }
}
signed main()
{
    read(n);read(Q);
    for(int i=1; i<=n; i++)
        read(a[i]);
    op[0]=2;
    for(int i=1; i<=Q; i++)
    {
        int rt;
        read(rt);read(op[i]);read(k[i]);
        if(op[i]==1)
            read(x[i]);
        vec[rt].push_back(i);
    }
    dfs(0);
    for(int i=1; i<=Q; i++)
        if(op[i]==2)
            write(ans[i]),pc('\n');
    return 0;
}

可持久化权值线段树(主席树)

区间 \(k\) 小值

时间复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() readchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+25)
char buf1[SIZ];
char *p1=buf1,*p2=buf1;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(2e5+5)
int n,m,Q;
int a[N],b[N];
int T[N],tot;
struct node
{
    int ch[2],sum;
}t[N<<5];
#define ls(at) t[at].ch[0]
#define rs(at) t[at].ch[1]
int build(int l,int r)
{
    int at=++tot,mid=(l+r)>>1;
    if(l<r)
    {
        ls(at)=build(l,mid);
        rs(at)=build(mid+1,r);
    }
    return at;
}
int update(int pre,int l,int r,int x)
{
    int at=++tot,mid=(l+r)>>1;
    t[at]=t[pre];++t[at].sum;
    if(l<r)
    {
        if(x<=mid)ls(at)=update(ls(pre),l,mid,x);
        else rs(at)=update(rs(pre),mid+1,r,x);
    }
    return at;
}
int query(int u,int v,int l,int r,int k)
{
    if(l==r)return l;
    int x=t[ls(v)].sum-t[ls(u)].sum;
    int mid=(l+r)>>1;
    if(x>=k)return query(ls(u),ls(v),l,mid,k);
    else return query(rs(u),rs(v),mid+1,r,k-x);
}
void init()
{
    sort(b+1,b+1+n);
    m=unique(b+1,b+1+n)-b-1;
    T[0]=build(1,m);
    for(int i=1; i<=n; i++)
    {
        a[i]=lower_bound(b+1,b+1+m,a[i])-b;
        T[i]=update(T[i-1],1,m,a[i]);
    }
}
signed main()
{
    read(n);read(Q);
    for(int i=1; i<=n; i++)
        read(a[i]),b[i]=a[i];
    init();
    while(Q--)
    {
        int l,r,k;read(l);read(r);read(k);
        write(b[query(T[l-1],T[r],1,m,k)]);
        pc('\n');
    }
    return 0;
}

动态树(LCT)

模板题:P3690 【模板】动态树(LCT)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e5+5)
#define gc() getchar()
#define pc(a) putchar(a)
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){k=-k;pc('-');}
    if(k>9)write(k/10);
    pc(k%10+'0');
}
int n,Q;
namespace LCT
{
    struct node
    {
        int ch[2],num,fa,ans,tag;
    }t[N];
    #define isroot(x) ((t[t[x].fa].ch[0]!=x)&&(t[t[x].fa].ch[1]!=x))
    void pushr(int x)
    {
        swap(t[x].ch[0],t[x].ch[1]);
        t[x].tag^=1;
    }
    void push_up(int x)
    {
        t[x].ans=t[t[x].ch[0]].ans
        ^t[t[x].ch[1]].ans^t[x].num;
    }
    void push_down(int x)
    {
        if(t[x].tag)
        {
            if(t[x].ch[0])pushr(t[x].ch[0]);
            if(t[x].ch[1])pushr(t[x].ch[1]);
            t[x].tag=0;
        }
    }
    void push_all(int x)
    {
        if(!isroot(x))push_all(t[x].fa);
        push_down(x);
    }
    void rotate(int x)
    {
        int y=t[x].fa;
        int z=t[y].fa;
        int k=t[y].ch[1]==x;
        if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;
        t[x].fa=z;
        t[y].ch[k]=t[x].ch[k^1];
        t[t[x].ch[k^1]].fa=y;
        t[x].ch[k^1]=y;
        t[y].fa=x;
        push_up(y);
        push_up(x);
    }
    void splay(int x)
    {
        push_all(x);
        while(!isroot(x))
        {
            int y=t[x].fa;
            int z=t[y].fa;
            if(!isroot(y))
            (t[z].ch[1]==y)^(t[y].ch[1]==x)?rotate(x):rotate(y);
            rotate(x);
        }
    }
    void access(int x)
    {
        for(int y=0;x;y=x,x=t[x].fa)
            splay(x),t[x].ch[1]=y,push_up(x);
    }
    void make_root(int x)
    {
        access(x);splay(x);
        pushr(x);
    }
    int find_root(int x)
    {
        access(x);splay(x);
        while(t[x].ch[0])push_down(x),x=t[x].ch[0];
        splay(x);
        return x;
    }
    void split(int x,int y)
    {
        make_root(x);
        access(y);splay(y);
    }
    void link(int x,int y)
    {
        make_root(x);
        if(find_root(y)!=x)t[x].fa=y;
    }
    void cut(int x,int y)
    {
        make_root(x);
        if(find_root(y)==x&&t[y].fa==x&&!t[y].ch[0])
        {
            t[x].ch[1]=t[y].fa=0;
            push_up(x);
        }
    }
}
signed main()
{
    using namespace LCT;
    read(n);read(Q);
    for(int i=1; i<=n; i++)
        read(t[i].num);
    while(Q--)
    {
        int op,x,y;read(op);read(x);read(y);
        if(op==0){split(x,y);write(t[y].ans);pc('\n');}
        if(op==1)link(x,y);
        if(op==2)cut(x,y);
        if(op==3)splay(x),t[x].num=y;
    }
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录