【模板】数据结构

并查集

并查集
//P3367 【模板】并查集
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int fa[N],n,m;

int find( int x )
{
        return x==fa[x] ? x : fa[x]=find( fa[x] );
}

int main()
{
        scanf( "%d%d",&n,&m );

        for ( int i=1; i<=n; i++ )
                fa[i]=i;
        
        for ( int i=1; i<=m; i++ )
        {
                int opt,x,y; scanf( "%d%d%d",&opt,&x,&y );
                int fx=find( x ),fy=find( y );
                if ( opt==1 )
                {
                        if ( fx!=fy ) fa[fx]=fa[fy]; 
                }
                else printf( "%c\n",fx==fy ? 'Y' : 'N' );
        }
}
种类并查集
//AcWing240 食物链 
const int N=2e5+10;
int fa[N];      //同类,捕食,天敌
int n,m,k,x,y,ans=0;

int find( int x )
{
    return x==fa[x] ? x : fa[x]=find(fa[x]);
}

void merge( int x,int y )
{
    fa[find(x)]=find(y);
}

int main()
{
    scanf( "%d%d",&n,&m );
    for ( int i=1; i<=3*n; i++ )
        fa[i]=i;
    for ( int i=1; i<=m; i++ )
    {
        int opt,x,y; scanf( "%d%d%d",&opt,&x,&y );
        if ( x>n || y>n ) ans++;
        else if ( opt==1 )
        {
            if ( find( x )==find( y+n ) || find( x )==find( y+n+n ) ) ans++;    
            //x,y是同类,但x被y吃,或x是y的天敌 
            else 
            {
                merge( x,y ); merge( x+n,y+n ); merge( x+n+n,y+n+n );
            }
        }
        else
        {
            if ( x==y || find(x)==find(y) || find(x)==find(y+n) ) ans++;
            //x就是y,或xy为同类,或y吃x
            else
            {
                merge( x,y+n+n );       //x及其同类被y吃 
                merge( x+n,y );         //x的天敌是y 
                merge( x+n+n,y+n );             //x吃y的天敌 
            }
                        
        }
    }

    printf( "%d",ans );
}
可持久化并查集
//BZOJ3674,Luogu3402
//Author: RingweEH
const int N=2e5+10;
int n,m,rt[N*20];
struct Persistant_Union_Set
{
    int lc[N*20],rc[N*20],fa[N*20],dep[N*20],cnt;
    void build( int &now,int l,int r )
    {
        now=++cnt;
        if ( l==r ) { fa[now]=l; return; }
        int mid=(l+r)>>1;
        build( lc[now],l,mid ); build( rc[now],mid+1,r );
    }
    void merge( int &now,int pre,int l,int r,int pos,int fat )
    {
        now=++cnt; lc[now]=lc[pre],rc[now]=rc[pre];
        if ( l==r )
        {
            fa[now]=fat; dep[now]=dep[pre]; return;
        }
        int mid=(l+r)>>1;
        if ( pos<=mid ) merge( lc[now],lc[pre],l,mid,pos,fat );
        else merge( rc[now],rc[pre],mid+1,r,pos,fat );
    }
    void update( int now,int l,int r,int pos )
    {
        if ( l==r ) { dep[now]++; return; }
        int mid=(l+r)>>1;
        if ( pos<=mid ) update( lc[now],l,mid,pos );
        else update( rc[now],mid+1,r,pos );
    }
    int query( int now,int l,int r,int pos )
    {
        if ( l==r ) return now;
        int mid=(l+r)>>1;
        if ( pos<=mid ) return query( lc[now],l,mid,pos );
        else return query( rc[now],mid+1,r,pos );
    }
    int find( int now,int pos )
    {
        int tmp=query( now,1,n,pos );
        if ( fa[tmp]==pos ) return tmp;
        return find( now,fa[tmp] );
    }
}s;

int main()
{
    n=read(); m=read();
    s.build( rt[0],1,n );
    for ( int i=1; i<=m; i++ )
    {
        int opt=read(),x=read(),y;
        if ( opt==1 )
        {
            y=read(); rt[i]=rt[i-1];
            int fx=s.find( rt[i],x ),fy=s.find( rt[i],y );
            if ( s.fa[fx]^s.fa[fy] )
            {
                if ( s.dep[fx]>s.dep[fy] ) swap( fx,fy );
                s.merge( rt[i],rt[i-1],1,n,s.fa[fx],s.fa[fy] );
                if ( s.dep[fx]==s.dep[fy] ) s.update( rt[i],1,n,s.fa[fy] );
            }
        }
        else if ( opt==2 ) rt[i]=rt[x];
        else 
        {
            y=read(); rt[i]=rt[i-1];
            int fx=s.find( rt[i],x ),fy=s.find( rt[i],y );
            if ( s.fa[fx]==s.fa[fy] ) printf( "1\n" );
            else printf( "0\n" );
        }
    }
    return 0;
}

线段树

区间维护
//Scoi2010 序列操作
//Author: RingweEH
//菜鸡REH顶风作案
const int N=1e5+10;
int n,q,a[N];
struct SegmentTree
{
    struct Node
    {
        int cntw,cntb,lcntw,rcntw,lcntb,rcntb,mxw,mxb;
        //w个数,b个数,左/右数w个数,左/右数b个数,连续w/b最大值
        Node( int _cntw=0,int _cntb=0,int _lcntw=0,int _lcntb=0,
            int _rcntw=0,int _rcntb=0,int _mxw=0,int _mxb=0 )
        {
            cntw=_cntw; cntb=_cntb; lcntw=_lcntw; lcntb=_lcntb;
            rcntb=_rcntb; rcntw=_rcntw; mxw=_mxw; mxb=_mxb;
        }
        Node operator + ( const Node &tmp ) const
        {
            Node res;
            res.cntw=cntw+tmp.cntw; res.cntb=cntb+tmp.cntb;
            res.lcntw=cntb ? lcntw : cntw+tmp.lcntw;
            res.lcntb=cntw ? lcntb : cntb+tmp.lcntb;
            res.rcntw=tmp.cntb ? tmp.rcntw : tmp.cntw+rcntw;
            res.rcntb=tmp.cntw ? tmp.rcntb : tmp.cntb+rcntb;
            res.mxw=max( max(mxw,tmp.mxw),rcntw+tmp.lcntw );
            res.mxb=max( max(mxb,tmp.mxb),rcntb+tmp.lcntb );
            return res;
        }
    }tr[N<<2];
    int len[N<<2],tag1[N<<2],tag2[N<<2];
    //区间长度,区间赋值标记(-1/0/1),区间取反(0/1)
    void Operate( int pos,int opt ) 
    {
        Node &te=tr[pos];
        if ( opt==0 )   //reset( 0 )
        {
            tag2[pos]=tag1[pos]=0; int t=len[pos];
            te=Node( 0,t,0,t,0,t,0,t );
        }
        if ( opt==1 )   //reset( 1 )
        {
            tag2[pos]=0,tag1[pos]=1; int t=len[pos];
            te=Node( t,0,t,0,t,0,t,0 );
        }
        if ( opt==2 )   //flip
        {
            tag2[pos]^=1; 
            swap( te.cntw,te.cntb ); swap( te.mxb,te.mxw );
            swap( te.lcntw,te.lcntb ); swap( te.rcntw,te.rcntb );
        }
    }
    void Pushdown( int pos )
    {
        if ( tag1[pos]>-1 ) 
            Operate( pos<<1,tag1[pos] ),Operate( pos<<1|1,tag1[pos] );
        if ( tag2[pos] ) 
            Operate( pos<<1,2 ),Operate( pos<<1|1,2 );
        tag1[pos]=-1; tag2[pos]=0; 
    }
    void Modify( int pos,int L,int R,int l,int r,int val )
    {
        if ( r<L || R<l ) return;
        if ( l<=L && R<=r ) { Operate( pos,val ); return; }
        Pushdown( pos ); int mid=(L+R)>>1;
        Modify( pos<<1,L,mid,l,r,val ); Modify( pos<<1|1,mid+1,R,l,r,val );
        tr[pos]=tr[pos<<1]+tr[pos<<1|1];
    }
    Node Query( int pos,int L,int R,int l,int r )
    {
        if ( r<L || R<l ) return Node();
        if ( l<=L && R<=r ) return tr[pos];
        Pushdown( pos ); int mid=(L+R)>>1;
        Node lc=Query(pos<<1,L,mid,l,r),rc=Query(pos<<1|1,mid+1,R,l,r);
        return lc+rc;
    }
    void Build( int pos,int L,int R )
    {
        len[pos]=R-L+1; tag1[pos]=-1;
        if ( L==R )
        {
            int t=a[L]; tr[pos]=Node(t,t^1,t,t^1,t,t^1,t,t^1 );
            return;
        }
        int mid=(L+R)>>1;
        Build( pos<<1,L,mid ); Build( pos<<1|1,mid+1,R );
        tr[pos]=tr[pos<<1]+tr[pos<<1|1];
    }
    int Answer( int l,int r,int opt )
    {
        Node res=Query( 1,1,n,l,r );
        if ( opt==3 ) return res.cntw;
        else return res.mxw;
    }
    //w,b,lw,lb,rw,rb,mw,mb;
}Tr;
 
int main()
{
    n=read(); q=read();
    for ( int i=1; i<=n; i++ )
        a[i]=read();
 
    Tr.Build(1,1,n);
    while ( q-- )
    {
        int opt=read(),l=read()+1,r=read()+1;
        if ( opt<3 ) Tr.Modify( 1,1,n,l,r,opt );
        else printf( "%d\n",Tr.Answer(l,r,opt) );
    }
 
    return 0;
}
LazyTag模板
//Author: RingweEH
//Tyvj1518 CPU监控
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
ll max( ll a,ll b ) { return a>b ? a : b; }
ll read()
{
    ll x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

#define lson pos<<1
#define rson pos<<1|1
const int N=1e5+10,INF=0x3f3f3f3f;
struct Node
{
	int val,add,assign,lasv,lasad,lasas;
};
void bmax( int &x,int y ) { x=(x>y) ? x : y; }
struct SegmentTree
{
	Node tr[N<<2];
	void Pushup( int pos )
	{
		tr[pos].val=max( tr[lson].val,tr[rson].val );
		tr[pos].lasv=max( tr[lson].lasv,tr[rson].lasv );
	}
	void Upd_Add( int pos,int add,int lasad )
	{
		if ( tr[pos].assign!=-INF )		//有区间赋值操作
		{
			bmax( tr[pos].lasas,tr[pos].assign+lasad );	//遗留赋值和当前赋值+遗留add取max
			bmax( tr[pos].lasv,tr[pos].val+lasad );		//遗留mx和当前mx+遗留add取max
			tr[pos].assign+=add; tr[pos].val+=add;
		}
		else	//没有区间赋值
		{
			bmax( tr[pos].lasad,tr[pos].add+lasad );	//遗留add和当前add+遗留add取mx
			bmax( tr[pos].lasv,tr[pos].val+lasad );		//遗留mx和当前mx+遗留add取mx
			tr[pos].add+=add; tr[pos].val+=add;
		}
	}
	void Upd_Assign( int pos,int ass,int lasas )
	{
		bmax( tr[pos].lasas,lasas );	//和当前遗留ass取max
		bmax( tr[pos].lasv,lasas );		//更新遗留mx
		tr[pos].assign=ass; tr[pos].val=ass;	//更新当前ass和mx
	}
	void Pushdown( int pos )
	{
		Upd_Add( lson,tr[pos].add,tr[pos].lasad );	//下放add标记
		Upd_Add( rson,tr[pos].add,tr[pos].lasad );	
		tr[pos].add=tr[pos].lasad=0;
		if ( tr[pos].assign!=-INF )		//下放ass标记,因为优先级高
		{
			Upd_Assign( lson,tr[pos].assign,tr[pos].lasas );
			Upd_Assign( rson,tr[pos].assign,tr[pos].lasas );
			tr[pos].assign=tr[pos].lasas=-INF;		//注意不是赋值成0,因为有负数
		}
	}
	void Modify_Add( int pos,int L,int R,int l,int r,int val )
	{
		if ( L>r || R<l ) return;
		if ( l<=L && R<=r ) { Upd_Add( pos,val,val ); return; }
		Pushdown( pos ); int mid=(L+R)>>1;
		Modify_Add( lson,L,mid,l,r,val ); Modify_Add( rson,mid+1,R,l,r,val );
		Pushup( pos );
	}
	void Modify_Ass( int pos,int L,int R,int l,int r,int val )
	{
		if ( L>r || R<l ) return;
		if ( l<=L && R<=r ) { Upd_Assign( pos,val,val ); return; }
		Pushdown( pos ); int mid=(L+R)>>1;
		Modify_Ass( lson,L,mid,l,r,val ); Modify_Ass( rson,mid+1,R,l,r,val );
		Pushup( pos );
	}
	int Query( int pos,int L,int R,int l,int r,int opt )
	{
		if ( L>r || R<l ) return -INF;
		if ( l<=L && R<=r ) return opt ? tr[pos].lasv : tr[pos].val;
		Pushdown( pos ); int mid=(L+R)>>1;
		return max( Query( lson,L,mid,l,r,opt ),Query( rson,mid+1,R,l,r,opt ) );
	}
	void Build( int pos,int l,int r )
	{
		tr[pos].assign=tr[pos].lasas=-INF;
		if ( l==r )
		{
			tr[pos].val=tr[pos].lasv=read(); return;
		}
		int mid=(l+r)>>1;
		Build( lson,l,mid ); Build( rson,mid+1,r );
		Pushup( pos );
	}
}Tr;
char ch[5];

int main()
{
	int n=read(); Tr.Build(1,1,n); int q=read();
	while( q-- )
	{
		scanf( "%s",ch ); int x=read(),y=read(),z;
		if ( ch[0]=='Q' ) printf( "%d\n",Tr.Query(1,1,n,x,y,0) );
		else if ( ch[0]=='A' ) printf( "%d\n",Tr.Query(1,1,n,x,y,1) );
		else if ( ch[0]=='P' ) z=read(),Tr.Modify_Add(1,1,n,x,y,z);
		else z=read(),Tr.Modify_Ass(1,1,n,x,y,z);
	}
    return 0;
}
可持久化数组
//P3919 【模板】可持久化线段树 1(可持久化数组)
//Author: RingweEH
const int N=1e6+10;
int a[N],n,m,rt[N*20];
struct Persistable_SegmentTree
{
    int tl[N*20],tr[N*20],val[N*20],cnt;
    void build( int &now,int l,int r )
    {
        now=++cnt;
        if ( l==r ) { val[now]=a[l]; return; }
        int mid=(l+r)>>1;
        build( tl[now],l,mid ); build( tr[now],mid+1,r );
    }
    void insert( int &now,int pre,int l,int r,int pos,int v )
    {
        now=++cnt; tl[now]=tl[pre]; tr[now]=tr[pre]; val[now]=val[pre];
        if ( l==r ) { val[now]=v; return; }
        int mid=(l+r)>>1;
        if ( pos<=mid ) insert( tl[now],tl[pre],l,mid,pos,v );
        else insert( tr[now],tr[pre],mid+1,r,pos,v );
    }
    int query( int now,int l,int r,int pos )
    {
        if ( l==r ) return val[now];
        int mid=(l+r)>>1;
        if ( pos<=mid ) return query( tl[now],l,mid,pos );
        else return query( tr[now],mid+1,r,pos );
    }
}tr;

int main()
{
    n=read(); m=read();
    for ( int i=1; i<=n; i++ )
        a[i]=read();
    
    tr.build( rt[0],1,n );
    for ( int i=1; i<=m; i++ )
    {
        int view=read(),opt=read(),x=read(),y;
        if ( opt==1 ) y=read(),tr.insert( rt[i],rt[view],1,n,x,y );
        else printf( "%d\n",tr.query( rt[view],1,n,x ) ),rt[i]=rt[view];
    }
}
可持久化线段树2
//P3834 【模板】可持久化线段树 2(主席树)
//每一棵线段树维护一个区间的最值,然后按照可持久化的思想,每一棵新的树增加log个节点。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
struct node
{
    int l,r,sum;
}tr[N<<5];
int a[N],rt[N],n,m,tot=0;
vector<int> v;

int getid( int k )
{
    return lower_bound( v.begin(),v.end(),k )-v.begin()+1;
}

void build( int &trt,int l,int r )
{
    trt=++tot; tr[trt].sum=0;
    if ( l==r ) return;
    int mid=(l+r)>>1;
    build( tr[trt].l,l,mid ); build( tr[trt].r,mid+1,r );
}

void update( int l,int r,int &now,int las,int k )
{
    tr[++tot]=tr[las];
    now=tot; tr[tot].sum++;
    if ( l==r ) return;
    int mid=(l+r)>>1;
    if ( k<=mid ) update( l,mid,tr[now].l,tr[las].l,k );
    else update( mid+1,r,tr[now].r,tr[las].r,k );
}

int query( int l,int r,int x,int y,int k )
{
    if ( l==r ) return l;
    int mid=(l+r)>>1,cnt=tr[tr[y].l].sum-tr[tr[x].l].sum;
    if ( cnt>=k ) return query( l,mid,tr[x].l,tr[y].l,k );
    else return query( mid+1,r,tr[x].r,tr[y].r,k-cnt );
}

int main()
{
    scanf( "%d%d",&n,&m );
    for ( int i=1; i<=n; i++ )
        scanf( "%d",&a[i] ),v.push_back( a[i] );
    
    sort( v.begin(),v.end() );
    v.erase( unique(v.begin(),v.end()),v.end() );
    build( rt[0],1,n );
    for ( int i=1; i<=n; i++ )
        update( 1,n,rt[i],rt[i-1],getid(a[i]) );
    
    while ( m-- )
    {
        int l,r,k; scanf( "%d%d%d",&l,&r,&k );
        printf( "%d\n",v[query(1,n,rt[l-1],rt[r],k)-1] );
    }
}
动态区间第 K 小
//P2617 Dynamic Rankings
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct SegmentTree
{
        int val,l,r;
}tr[N*400];
struct Question
{
        bool typ; int l,r,k,pos,t;
}q[N];
int n,m,a[N],rt[N],len,tot,tmp[2][20],cnt[2],num[N<<1];
char opt[10];

int lowbit( int x ) { return x&(-x); }

void modify( int &p,int l,int r,int pos,int val )
{
        if ( !p ) p=++tot;
        tr[p].val+=val;
        if ( l==r ) return;
        int mid=(l+r)>>1;
        if ( pos<=mid ) modify( tr[p].l,l,mid,pos,val );
        else modify( tr[p].r,mid+1,r,pos,val );
}

void init_modify( int x,int val )
{
        int k=lower_bound( num+1,num+len+1,a[x] )-num;
        for ( int i=x; i<=n; i+=lowbit(i) ) 
                modify( rt[i],1,len,k,val );
}

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[1]; i++ )
                sum+=tr[tr[tmp[1][i]].l].val;
        for ( int i=1; i<=cnt[0]; i++ )
                sum-=tr[tr[tmp[0][i]].l].val;
        if ( k<=sum )
        {
                for ( int i=1; i<=cnt[1]; i++ )
                        tmp[1][i]=tr[tmp[1][i]].l;
                for ( int i=1; i<=cnt[0]; i++ )
                        tmp[0][i]=tr[tmp[0][i]].l;
                return query( l,mid,k );
        }
        else 
        {
                for ( int i=1; i<=cnt[1]; i++ )
                        tmp[1][i]=tr[tmp[1][i]].r;
                for ( int i=1; i<=cnt[0]; i++ )
                        tmp[0][i]=tr[tmp[0][i]].r;
                return query( mid+1,r,k-sum );
        }
}

int init_query( int l,int r,int k )
{
        memset( tmp,0,sizeof(tmp) );
        cnt[0]=cnt[1]=0;
        for ( int i=r; i; i-=lowbit(i) )
                tmp[1][++cnt[1]]=rt[i];
        for ( int i=l-1; i; i-=lowbit(i) )
                tmp[0][++cnt[0]]=rt[i];
        return query( 1,len,k );
}

int main()
{
        scanf( "%d%d",&n,&m );
        for ( int i=1; i<=n; i++ )
                scanf( "%d",&a[i] ),num[++len]=a[i];
        for ( int i=1; i<=m; i++ )
        { 
                scanf( "%s",opt );
                q[i].typ=(opt[0]=='Q');
                if ( q[i].typ ) scanf( "%d%d%d",&q[i].l,&q[i].r,&q[i].k );
                else scanf( "%d%d",&q[i].pos,&q[i].t ),num[++len]=q[i].t;
        }
//printf( "input has done." );
        sort( num+1,num+1+len ); len=unique( num+1,num+1+len )-num-1;
        for ( int i=1; i<=n; i++ )
                init_modify( i,1 );
        for ( int i=1; i<=m; i++ )
                if ( q[i].typ ) printf( "%d\n",num[init_query(q[i].l,q[i].r,q[i].k)] );
                else
                {
                        init_modify( q[i].pos,-1 ); a[q[i].pos]=q[i].t; init_modify( q[i].pos,1 );
                }               
}
树上路径第 K 小
//P2633 Count on a tree
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=2e6+10;
struct edge
{
        int to,nxt;
}e[N<<1];
int n,m,s,lasans=0,tot,cnt,head[N];
int a[N],tmp[N],fa[N][35],dep[N],rt[M]={0},ls[M]={0},rs[M]={0},siz[M]={0};

void add( int u,int v )
{
        e[++tot]=(edge){v,head[u]}; head[u]=tot;
}

void modify( int &rt,int las,int l,int r,int val )
{
        if ( !rt ) rt=++cnt;
        if ( l==r ) { siz[rt]++; return; }
        int mid=(l+r)>>1;
        if ( mid>=val ) modify( ls[rt],ls[las],l,mid,val ),rs[rt]=rs[las];
        else modify( rs[rt],rs[las],mid+1,r,val ),ls[rt]=ls[las];
        siz[rt]=siz[ls[rt]]+siz[rs[rt]];
}

int query( int rt1,int rt2,int rt3,int rt4,int l,int r,int k )
{
        if ( l==r ) return l;
        int mid=(l+r)>>1,tmp=siz[ls[rt1]]+siz[ls[rt2]]-siz[ls[rt3]]-siz[ls[rt4]];
        if ( tmp>=k ) return query( ls[rt1],ls[rt2],ls[rt3],ls[rt4],l,mid,k );
        else return query( rs[rt1],rs[rt2],rs[rt3],rs[rt4],mid+1,r,k-tmp );
}

void dfs( int u,int fat )
{
        dep[u]=dep[fat]+1;
        for ( int i=head[u]; i; i=e[i].nxt )
        {
                int v=e[i].to;
                if ( v==fa[u][0] ) continue;
                fa[v][0]=u; modify( rt[v],rt[u],1,s,a[v] ); dfs( v,u );
        }
}

int lca( int x,int y )
{
        if ( dep[x]<dep[y] ) swap( x,y );
        int del=dep[x]-dep[y];
        for ( int i=0; (1<<i)<=del; i++ )
                if ( (1<<i)&del ) x=fa[x][i];
        for ( int i=20; i>=0; i-- )
                if ( fa[x][i] != fa[y][i] ) x=fa[x][i],y=fa[y][i];
        return x==y ? x : fa[x][0];
}

int main()
{
        scanf( "%d%d",&n,&m );
        for ( int i=1; i<=n; i++ )
                scanf( "%d",&tmp[i] ),a[i]=tmp[i];
        //----------------input-----------------
        sort( tmp+1,tmp+1+n ); s=unique( tmp+1,tmp+1+n )-tmp;
        for ( int i=1,u,v; i<n; i++ )
                scanf( "%d%d",&u,&v ),add( u,v ),add( v,u );
        for ( int i=1; i<=n; i++ )
                a[i]=lower_bound( tmp+1,tmp+1+s,a[i] )-tmp;
        //--------------离散化-------------------
        modify( rt[1],rt[0],1,s,a[1] ); dfs( 1,0 ); int lim=log2(n);
        for ( int k=1; k<=lim; k++ )
         for ( int i=1; i<=n; i++ )
                fa[i][k]=fa[fa[i][k-1]][k-1];
        //-------------prework------------------
        while ( m-- )
        {
                int u,v,k; scanf( "%d%d%d",&u,&v,&k );
                u^=lasans; 
                int _lca=lca(u,v),ans=tmp[query(rt[u],rt[v],rt[_lca],rt[fa[_lca][0]],1,s,k)];
                printf( "%d\n",ans ); lasans=ans;
        }
}
李超线段树
//Author: RingweEH
//P4097 [HEOI2013]Segment
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

#define ls pos<<1
#define rs pos<<1|1
const int N=1e5+10,Mod=39989;
int n,m,num[(Mod+10)<<2];
bool vis[(Mod+10)<<2];
struct Line{db k,b; Line(db _k=0,db _b=0):k(_k),b(_b){} }seg[N];
db F(Line a,int x){return a.k*x+a.b;}
db IntSec(Line a,Line b){return (b.b-a.b)/(a.k-b.k);}
int cmp( int a,int b,int x ) { return F(seg[a],x)>F(seg[b],x) ? a : b; }

void Insert( int pos,int L,int R,int l,int r,int x )
{
	int mid=(L+R)>>1;
	if ( l<=L && R<=r )
	{
		if ( !vis[pos] ) { num[pos]=x,vis[pos]=1; return; } //None
		int las=num[pos],nw=x;
		db lyn=F(seg[nw],L),ryn=F(seg[nw],R);
		db lyl=F(seg[las],L),ryl=F(seg[las],R);
		if ( lyn<=lyl && ryn<=ryl ) return; 	//Failed.
		if ( lyn>=lyl && ryn>=ryl ) { num[pos]=nw; return; }	//Win.
		db inp=IntSec(seg[las],seg[nw]);
		if ( lyn>=lyl )
			if ( inp<=mid ) Insert(ls,L,mid,l,r,nw);
			else Insert(rs,mid+1,R,l,r,las),num[pos]=nw;
		else
			if ( inp>mid ) Insert(rs,mid+1,R,l,r,nw);
			else Insert(ls,L,mid,l,r,las),num[pos]=nw;
		return;
	}	
	if ( mid>=l )Insert(ls,L,mid,l,r,x);
	if ( mid<r ) Insert(rs,mid+1,R,l,r,x);
}
int Query( int pos,int l,int r,int val )
{
	int res=0,mid=(l+r)>>1,tmp;
	if ( vis[pos] ) res=cmp(res,num[pos],val);
	if ( l==r ) return res;
	if ( mid>=val ) tmp=Query(ls,l,mid,val),res=cmp(res,tmp,val);
	else tmp=Query(rs,mid+1,r,val),res=cmp(res,tmp,val);
	return res;
}

int ans;
int getdata(int x,int Mod){return (x+ans-1)%Mod+1;}
int main()
{
	n=read();
	for ( int i=1,opt,x1,y1,x2,y2,k; i<=n; i++ )
	{
		opt=read();
		if ( opt )
		{
			x1=read(),y1=read(),x2=read(),y2=read();
			x1=getdata(x1,Mod); y1=getdata(y1,1e9);
			x2=getdata(x2,Mod); y2=getdata(y2,1e9);
			seg[++m]=(x1==x2) ? Line(.0,(db)max(y1,y2)) : 
				Line((db)(y2-y1)/(x2-x1),-db(y2-y1)/(x2-x1)*x1+y1);
			Insert( 1,1,Mod,min(x1,x2),max(x1,x2),m );
		}
		else
		{
			k=read(); k=getdata(k,Mod);
			ans=Query(1,1,Mod,k); printf("%d\n",ans );
		}
	}

	return 0;
}
线段树合并
//Author: RingweEH
//P4556
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

const int N=1e5+10,L=18;
int n,m,dep[N],fa[N][L],rt[N],cnt=0;
int head[N],num=0;
int x[N],y[N],z[N],d[N],tot,ans[N];
struct Edge { int nxt,to; }e[N<<1];
struct Node { int l,r,v,pos; }tr[(N<<1)*L*2];

void Adde( int u,int v ) { e[++num]=(Edge){head[u],v}; head[u]=num; }
void DFS1( int x )
{
    for ( int i=1; i<L && fa[x][i-1]; i++ )
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for ( int i=head[x]; i; i=e[i].nxt )
    {
        int v=e[i].to;
        if ( v==fa[x][0] ) continue;
        fa[v][0]=x; dep[v]=dep[x]+1; DFS1( v );
    }
}
int LCA( int x,int y )
{
    if ( dep[x]<dep[y] ) swap( x,y );
    for ( int i=L-1; ~i; i-- )
        if ( dep[x]-(1<<i)>=dep[y] ) x=fa[x][i];
    if ( x==y ) return y;
    for ( int i=L-1; ~i; i-- )
        if ( fa[x][i]!=fa[y][i] ) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
void Pushup( int p )
{
    tr[p].v=max( tr[tr[p].l].v,tr[tr[p].r].v );
    if ( tr[tr[p].l].v>=tr[tr[p].r].v ) tr[p].pos=tr[tr[p].l].pos;
    else tr[p].pos=tr[tr[p].r].pos;
}
void Modify( int &p,int l,int r,int x,int k )
{
    if ( !p ) p=++cnt;
    if ( l==r ) { tr[p].v+=k; tr[p].pos=tr[p].v ? l : 0; return; }
    int mid=(l+r)/2;
    if ( x<=mid ) Modify( tr[p].l,l,mid,x,k );
    else Modify( tr[p].r,mid+1,r,x,k );
    Pushup( p );
}
void Merge( int &p,int &q,int l,int r )
{
    if ( !q ) return;
    if ( !p ) { p=q; return; }
    if ( l==r ) { tr[p].v+=tr[q].v; tr[p].pos=tr[p].v ? l : 0; return; }
    int mid=( l+r )/2;
    Merge( tr[p].l,tr[q].l,l,mid ); Merge( tr[p].r,tr[q].r,mid+1,r );
    Pushup( p );
}
void DFS( int x )
{
    for ( int i=head[x]; i; i=e[i].nxt )
    {
        int v=e[i].to;
        if ( v==fa[x][0] ) continue;
        DFS( v ); Merge( rt[x],rt[v],1,tot );
    }
    ans[x]=tr[rt[x]].pos;
}

int main()
{
//freopen( "exam.in","r",stdin );

    n=read(); m=read();
    for ( int i=1,u,v; i<n; i++ )
        u=read(),v=read(),Adde( u,v ),Adde( v,u );
    for ( int i=1; i<=m; i++ )
        x[i]=read(),y[i]=read(),z[i]=read(),d[i]=z[i];

    sort( d+1,d+1+m ); tot=unique( d+1,d+1+m )-d-1; 
    DFS1( 1 );
    for ( int i=1; i<=m; i++ )
    {
        int xx=x[i],yy=y[i],zz=lower_bound( d+1,d+1+tot,z[i] )-d,p=LCA( xx,yy );
        Modify( rt[xx],1,tot,zz,1 ); Modify( rt[yy],1,tot,zz,1 ); 
        Modify( rt[p],1,tot,zz,-1 ); 
        if ( fa[p][0] ) Modify( rt[fa[p][0]],1,tot,zz,-1 );
    }
    DFS( 1 );

    for ( int i=1; i<=n; i++ ) printf( "%d\n",d[ans[i]] );

    return 0;
}
线段树分裂
//Author: RingweEH
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

const int N=2e5+10;
int n,m,rtcnt,bkcnt,cnt=1;
int cyc[N<<5],son[N<<5][2],rt[N];
ll tr[N<<5];

int NewNode() { return bkcnt ? cyc[bkcnt--] : ++rtcnt; }
void Delete( int pos ) { cyc[++bkcnt]=pos; son[pos][0]=son[pos][1]=tr[pos]=0; }
void Modify( int &pos,int l,int r,int x,int v )
{
	if ( !pos ) pos=NewNode(); 
	tr[pos]+=v;
	if ( l==r ) return;
	int mid=(l+r)>>1;
	(x<=mid) ? Modify(son[pos][0],l,mid,x,v) : Modify(son[pos][1],mid+1,r,x,v);
}
ll Query( int pos,int L,int R,int l,int r )
{
	if ( r<L || R<l ) return 0;
	if ( l<=L && R<=r ) return tr[pos];
	int mid=(L+R)>>1;
	return Query(son[pos][0],L,mid,l,r)+Query(son[pos][1],mid+1,R,l,r);
}
int kth( int pos,int l,int r,int rk )
{
	if ( l==r ) return l;
	int mid=(l+r)>>1;
	return (tr[son[pos][0]]>=rk) ? 
	kth(son[pos][0],l,mid,rk) : kth(son[pos][1],mid+1,r,rk-tr[son[pos][0]]);
}
int Merge( int p,int q )
{
	if ( !p || !q ) return p+q;
	tr[p]+=tr[q];
	son[p][0]=Merge(son[p][0],son[q][0]);
	son[p][1]=Merge(son[p][1],son[q][1]);
	Delete(q); return p;
}
void Split( int p,int &q,ll rk )
{
	if ( p==0 ) return; q=NewNode();
	ll val=tr[son[p][0]];
	(rk>val) ? Split(son[p][1],son[q][1],rk-val) : swap(son[p][1],son[q][1]);
	if ( rk<val ) Split(son[p][0],son[q][0],rk);
	tr[q]=tr[p]-rk; tr[p]=rk;
}

int main()
{
//freopen( "exam.in","r",stdin );

	n=read(); m=read();
	for ( int i=1,x; i<=n; i++ )
		x=read(),Modify(rt[1],1,n,i,x);

	for ( int i=1,opt,a,b,c; i<=m; i++ )
	{
		opt=read();
		if ( opt==0 )
		{
			a=read(); b=read(); c=read();
			ll t1=Query(rt[a],1,n,1,c);
			ll t2=Query(rt[a],1,n,b,c);
			int tmp=0;
			Split(rt[a],rt[++cnt],t1-t2); Split(rt[cnt],tmp,t2);
			rt[a]=Merge(rt[a],tmp);
		}
		else if ( opt==1 ) a=read(),b=read(),rt[a]=Merge(rt[a],rt[b]);
		else if ( opt==2 ) a=read(),b=read(),c=read(),Modify(rt[a],1,n,c,b);
		else if ( opt==3 ) a=read(),b=read(),c=read(),printf("%lld\n",Query(rt[a],1,n,b,c));
		else if ( opt==4 )
		{
			a=read(); b=read();
			if ( tr[rt[a]]<b ) { puts("-1"); continue; }
			printf("%d\n",kth(rt[a],1,n,b) );
		}
	}

	return 0;
}

平衡树

Splay
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct splay_node
{
    int fa,cnt,val,ch[2],siz;
}tr[N];
int rt,tot;

void upd( int x )
{
    tr[x].siz=tr[tr[x].ch[0]].siz+tr[tr[x].ch[1]].siz+tr[x].cnt;
}

void rotate( int x )
{
    int y=tr[x].fa,z=tr[y].fa;
    int k=( tr[y].ch[1]==x );
    tr[z].ch[(tr[z].ch[1]==y)]=x; tr[x].fa=z;
    tr[y].ch[k]=tr[x].ch[k^1]; tr[tr[x].ch[k^1]].fa=y;
    tr[x].ch[k^1]=y; tr[y].fa=x;
    upd( y ); upd( x );
}

void splay( int x,int s )
{
    while ( tr[x].fa!=s )
    {
        int y=tr[x].fa,z=tr[y].fa;
        if ( z!=s ) 
            if ( (tr[z].ch[0]==y) != (tr[y].ch[0]==x ) ) rotate( x );
            else rotate( y );
        rotate( x );
    }
    if ( s==0 ) rt=x;
}

void find( int x )          //val
{
    int u=rt;
    if ( !u ) return;
    while ( tr[u].ch[tr[u].val<x] && tr[u].val!=x ) 
        u=tr[u].ch[tr[u].val<x];
    splay( u,0 );
}

void insert(int x)
{
    int u=rt,fat=0;
    while ( u && tr[u].val!=x ) fat=u,u=tr[u].ch[tr[u].val<x];
    if ( u ) tr[u].cnt++;
    else 
    {
        tot++; u=tot;
        if ( fat ) tr[fat].ch[x>tr[fat].val]=u;
        tr[u].val=x; tr[u].fa=fat;
        tr[u].siz=1; tr[u].cnt=1;
        tr[u].ch[0]=tr[u].ch[1]=0;
    }
    splay( u,0 );
}

int Next( int x,int f )
{
    find( x );
    int u=rt;
    if ( tr[u].val>x && f ) return u;
    if ( tr[u].val<x && !f ) return u;
    u=tr[u].ch[f];
    while ( tr[u].ch[f^1] ) u=tr[u].ch[f^1]; 
    return u;
}

void Delete( int x )
{
    int last=Next( x,0 ),nxt=Next( x,1 );
    splay( last,0 ); splay( nxt,last );
    int del=tr[nxt].ch[0];
    if ( tr[del].cnt>1 ) tr[del].cnt--,splay( del,0 );
    else tr[nxt].ch[0]=0;
}

int kth( int x )
{
    int u=rt;
    if ( tr[u].siz<x )  return 0;
    while ( 1 )
    {
        int v=tr[u].ch[0];
        if ( x>tr[v].siz+tr[u].cnt ) x-=(tr[v].siz+tr[u].cnt),u=tr[u].ch[1];
        else if ( tr[v].siz>=x ) u=v;
        else return tr[u].val;
    }
}

int n;

int main()
{
    scanf( "%d",&n );
    insert( 1e9 ); insert( -1e9 ); rt=1; upd( 1 );
    for ( int i=1,opt,x; i<=n; i++ )
    {
        scanf( "%d%d",&opt,&x );
        if ( opt==1 ) insert( x );
        if ( opt==2 ) Delete( x );
        if ( opt==3 ) find( x ),printf( "%d\n",tr[tr[rt].ch[0]].siz );
        if ( opt==4 ) printf( "%d\n",kth(x+1) );
        if ( opt==5 ) printf( "%d\n",tr[Next( x,0 )].val );
        if ( opt==6 ) printf( "%d\n",tr[Next( x,1 )].val );
    }
}
FHQ
//P3369【模板】普通平衡树
//FHQ-Treap
#include <cstdio>
#include <algorithm>
#include <time.h>
using namespace std;
const int N=5e5+10;
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch<'0' || ch>'9' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch>='0' && ch<='9' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}
struct FHQTreap
{
    int l,r,val,rnd,siz;
}tr[N];
int cnt=0,rt=0,tx,ty,tz;

void update( int x )
{
    tr[x].siz=1+tr[tr[x].l].siz+tr[tr[x].r].siz;
}

int new_node( int val )
{
    tr[++cnt].siz=1; tr[cnt].val=val; tr[cnt].rnd=rand(); return cnt;
}

int merge( int x,int y )          
{
    if ( !x || !y ) return x+y;
    if ( tr[x].rnd<tr[y].rnd ) 
    {    //make y -> x's right child
        tr[x].r=merge( tr[x].r,y ); update( x ); return x;     
    }
    else
    {   //make x -> y's left child
        tr[y].l=merge( x,tr[y].l ); update( y ); return y;
    }   
}

void split( int now,int k,int &x,int &y )
{   //split a Treap by val
    if ( !now ) { x=y=0; return; }
    if ( tr[now].val<=k ) x=now,split( tr[now].r,k,tr[now].r,y );
    //now比k小,左子树+根节点→x,递归分割右子树
    else y=now,split( tr[now].l,k,x,tr[now].l );
    update( now );
}

int get_kth( int now,int k )
{
    while ( 1 )
    {
        if ( k<=tr[tr[now].l].siz ) now=tr[now].l;
        //k<=tr[l].size,the node must be in the left subtree
        else if ( k==tr[tr[now].l].siz+1 ) return now;
        //the kth node is exactly tree 'now'
        else k-=tr[tr[now].l].siz+1,now=tr[now].r;
        //k-=left subtree's size and 1 for the root,then search in the right subtree
    }
}

int main()
{
    srand( time(NULL) );
    int T; scanf( "%d",&T ); 
    while ( T-- )
    {
        int opt=read(),x=read();
        if ( opt==1 )           //insert
        {
            split( rt,x,tx,ty ); rt=merge( merge(tx,new_node(x)),ty );
        }
        if ( opt==2 )               //delete
        {
            split( rt,x,tx,tz ); split( tx,x-1,tx,ty ); 
            ty=merge( tr[ty].l,tr[ty].r ); rt=merge( merge(tx,ty),tz );
        }
        if ( opt==3 )               //get rank by val
        {
            split( rt,x-1,tx,ty ); printf( "%d\n",tr[tx].siz+1 ); rt=merge( tx,ty );
        }
        if ( opt==4 ) printf( "%d\n",tr[get_kth(rt,x)].val );               //get val by rank
        if ( opt==5 )           //get pre node
        {
            split( rt,x-1,tx,ty ); printf( "%d\n",tr[get_kth(tx,tr[tx].siz)].val ); rt=merge( tx,ty );
        }
        if ( opt==6 )           //get suf node
        {
            split( rt,x,tx,ty ); printf( "%d\n",tr[get_kth(ty,1)].val ); rt=merge( tx,ty );
        }
    }
}
文艺平衡树(FHQ)
//P3391【模板】文艺平衡树(FHQ)
//其实就是要支持区间操作。这里是区间翻转
#include <cstdio>
#include <algorithm>
#include <time.h>
using namespace std;
const int N=5e5+10;
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch<'0' || ch>'9' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch>='0' && ch<='9' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}
struct FHQTreap
{
    int l,r,val,rnd,siz,mark;
}tr[N];
int cnt=0,rt=0,n,m;

void update( int x )
{
    tr[x].siz=1+tr[tr[x].l].siz+tr[tr[x].r].siz;
}

void pushdown( int x )
{
    if ( x && tr[x].mark )
    {
        tr[x].mark=0; swap( tr[x].l,tr[x].r );
        if ( tr[x].l ) tr[tr[x].l].mark^=1;
        if ( tr[x].r ) tr[tr[x].r].mark^=1;
    }
}

int new_node( int val )
{
    tr[++cnt].siz=1; tr[cnt].val=val; tr[cnt].rnd=rand(); 
    tr[cnt].mark=0; return cnt;
}

int merge( int x,int y )          
{
    if ( !x || !y ) return x+y;
    pushdown( x ); pushdown( y );
    if ( tr[x].rnd<tr[y].rnd ) 
    {    //make y -> x's right child
        tr[x].r=merge( tr[x].r,y ); update( x ); return x;     
    }
    else
    {   //make x -> y's left child
        tr[y].l=merge( x,tr[y].l ); update( y ); return y;
    }   
}

void split( int now,int k,int &x,int &y )
{
    if ( !now ) { x=y=0; return; }
    pushdown( now );
    if ( k<=tr[tr[now].l].siz ) y=now,split( tr[now].l,k,x,tr[now].l );
    else x=now,split( tr[now].r,k-tr[tr[now].l].siz-1,tr[now].r,y );
    update( now );
}

int build( int l,int r )
{
    if ( l>r ) return 0;
    int mid=(l+r)>>1,val=mid;
    int now=new_node( val );
    tr[now].l=build( l,mid-1 ); tr[now].r=build( mid+1,r );
    update( now );
    return now;
}

void dfs( int x )
{
    if ( !x ) return;
    pushdown( x );
    dfs( tr[x].l );
    printf( "%d ",tr[x].val );
    dfs( tr[x].r );
}

void reverse( int l,int r )
{
    int t1,t2,t3,t4;
    split( rt,r,t1,t2 ); split( t1,l-1,t3,t4 );
    tr[t4].mark^=1; rt=merge( merge( t3,t4 ),t2 );
}

int main()
{
    srand( time(0) );
    scanf( "%d%d",&n,&m );
    for ( int i=1; i<=n; i++ )
        rt=merge( rt,new_node(i) );
    for ( int l,r,i=1; i<=m; i++ )
        l=read(),r=read(),reverse( l,r );
    
    dfs( rt );
}
文艺平衡树(Splay)
//UVA11996 Jewel Magic
//Splay文艺平衡树+Hash找LCP
#include <bits/stdc++.h>
#define ull unsigned long long
#define l(x) ch[(x)][0]
#define r(x) ch[(x)][1]
using namespace std;
const int N=4e5+10,mod=1e9+7;
int n,m,ch[N][2],siz[N],val[N],mark[N],cnt=0,rt=0;
ull has[N],rehash[N],powe[N];
char s[N];

int new_node( int x )
{
    int u=++cnt; l(u)=r(u)=mark[u]=0; siz[u]=1;
    val[u]=has[u]=rehash[u]=x; return u;
}

void pushup( int x )
{
    siz[x]=siz[l(x)]+siz[r(x)]+1;
    has[x]=has[l(x)]*powe[siz[r(x)]+1]+val[x]*powe[siz[r(x)]]+has[r(x)];
    rehash[x]=rehash[r(x)]*powe[siz[l(x)]+1]+val[x]*powe[siz[l(x)]]+rehash[l(x)];
}

void reverse( int x )
{
    swap( l(x),r(x) ); swap( has[x],rehash[x] ); mark[x]^=1;
}

void pushdown( int x )
{
    if ( mark[x] ) mark[x]=0,reverse( l(x) ),reverse( r(x) );
}

void split( int x,int k,int &u,int &v )
{
    if ( !x ) { u=v=0; return; }
    pushdown( x );
    if ( k>=siz[l(x)]+1 ) u=x,split( r(x),k-siz[l(x)]-1,r(u),v ),pushup( u );
    else v=x,split( l(x),k,u,l(v) ),pushup( v );
}

void merge( int &x,int u,int v )
{
    if ( !u || !v ) { x=u|v; return; }
    if ( rand()%(siz[u]+siz[v])<siz[u] ) pushdown( u ),x=u,merge( r(x),r(u),v );
    else pushdown( v ),x=v,merge( l(x),u,l(v) );
    pushup( x );
}

void insert( int &x,int pos,int val )
{
    int L,R; split( x,pos,L,R );
    merge( L,L,new_node(val) ); merge( x,L,R );
}

void Delete( int &x,int pos )
{
    int t1,t2,t3; split( x,pos,t1,t2 ); split( t1,pos-1,t1,t3 );
    merge( x,t1,t2 );
}

void reverse( int &x,int l,int r )
{
    int t1,t2,t3; split( x,r,t1,t2 ); split( t1,l-1,t1,t3 );
    reverse( t3 ); merge( t1,t1,t3 ); merge( x,t1,t2 );
}

ull get_hash( int &x,int l,int r )
{
    int t1,t2,t3; split( x,r,t1,t2 ); split( t1,l-1,t1,t3 );
    ull res=has[t3]; merge( t1,t1,t3 ); merge( x,t1,t2 ); return res;
}

int get_LCP( int &x,int l,int r )
{
    int l1=0,r1=n-r+1,res,mid;
    while ( l1<=r1 )
    {
        mid=(l1+r1)>>1;
        if ( get_hash(x,l,l+mid-1)==get_hash(x,r,r+mid-1) ) res=mid,l1=mid+1;
        else r1=mid-1;
    }
    return res;
}

void build( int &x,int l=1,int r=n )
{
    if ( l>r ) return;
    int mid=(l+r)>>1;
    x=new_node( s[mid-1]-'0'+1 );
    build( l(x),l,mid-1 ); build( r(x),mid+1,r ); pushup( x );
}

int main()
{
    srand( time(0) ); powe[0]=1;
    for ( int i=1; i<N; i++ )
        powe[i]=powe[i-1]*mod;
    while( scanf( "%d%d",&n,&m )==2 )
    {
        cnt=0; scanf( "%s",s ); build( rt );
        while ( m-- )
        {
            int opt,t1,t2; scanf( "%d%d",&opt,&t1 );
            if ( opt!=2 ) scanf( "%d",&t2 );
            if ( opt==1 ) insert( rt,t1,t2+1 ),n++;
            else if ( opt==2 ) Delete( rt,t1 ),n--;
            else if ( opt==3 ) reverse( rt,t1,t2 );
            else if ( opt==4 ) printf( "%d\n",get_LCP( rt,t1,t2 ) );
        }
    }
}

LCT

维护链信息
//Author:RingweEH
//P3690 【模板】Link Cut Tree
#define lc tr[x][0]
#define rc tr[x][1]
const int N=3e5+10;
int fa[N],tr[N][2],val[N],sum[N],n,m,sta[N];
bool tag[N];

bool IsRoot( int x ) { return (tr[fa[x]][0]==x) || (tr[fa[x]][1]==x); }	
//判断Splay的根,如果是虚边显然不会是父亲的儿子
void Pushup( int x ) { sum[x]=sum[lc]^sum[rc]^val[x]; }
void Flip( int x ) { int tmp=lc; lc=rc; rc=tmp; tag[x]^=1; } //Splay翻转
void Pushdown( int x )		//标记下传,默认自己已经翻转完了
{
	if ( tag[x] )
	{
		if ( lc ) Flip( lc );
		if ( rc ) Flip( rc );
		tag[x]=0;
	}
}
void Rotate( int x )
{
	int y=fa[x],z=fa[y],kid=tr[y][1]==x,oth=tr[x][!kid];
	if ( IsRoot(y) ) tr[z][tr[z][1]==y]=x;
	tr[x][!kid]=y; tr[y][kid]=oth;
	if ( oth ) fa[oth]=y;
	fa[y]=x; fa[x]=z; Pushup(y);
}
void Splay( int x )
{
	int y=x,top=0; sta[++top]=y;
	while ( IsRoot(y) ) sta[++top]=y=fa[y];
	while ( top ) Pushdown(sta[top--]);
	while ( IsRoot(x) )
	{
		y=fa[x]; top=fa[y];
		if ( IsRoot(y) ) Rotate((tr[y][0]==x)^(tr[top][0]==y) ? x : y );
		Rotate(x);
	}
	Pushup(x);
}
void Access( int x ) { for ( int y=0; x; x=fa[y=x] ) Splay(x),rc=y,Pushup(x); } //取到根
void MakeRoot( int x ) { Access(x); Splay(x); Flip(x); }	//换根 
int FindRoot( int x )		//找原树上的树根
{
	Access(x); Splay(x);			//取出路径,转到根
	while ( lc ) Pushdown( x ),x=lc;		//每次往深度小的左子树走
	Splay(x); return x;	
}
void Split( int x,int y ) { MakeRoot(x); Access(y); Splay(y); }	//取出路径
void Link( int x,int y ) { MakeRoot(x); if ( FindRoot(y)^x ) fa[x]=y; } //加边
void Cut( int x,int y ) 	//删边
{
	MakeRoot(x);	//分别判连通性,父子关系,左儿子
	if ( FindRoot(y)==x && fa[y]==x && !tr[y][0] ) { fa[y]=tr[x][1]=0; Pushup(x); }
}

int main()
{
	n=read(); m=read();
	for ( int i=1; i<=n; i++ ) val[i]=read();
	while ( m-- )
	{
		int opt=read(),x=read(),y=read();
		if ( opt==0 ) Split( x,y ),printf("%d\n",sum[y] );
		else if ( opt==1 ) Link(x,y);
		else if ( opt==2 ) Cut(x,y);
		else if ( opt==3 ) Splay(x),val[x]=y;
	}

	return 0;
}
LCT维护最小生成树
//Author:RingweEH
//P4234 最小差值生成树
#define lc tr[x][0]
#define rc tr[x][1]
const int N=5e4+10,M=2e5+10,P=N+M,INF=0x3f3f3f3f;
int f[P],tr[P][2],mn[P],fa[N],val[P],n,m,ans;
bool tag[P],vis[M];
struct Edge
{
    int fro,to,len;
    bool operator < ( Edge tmp ) { return len<tmp.len; }
}e[M];
bool IsRoot( int x ) { return tr[f[x]][0]==x || tr[f[x]][1]==x; }
int vmin( int x,int y ) { return val[x]<val[y] ? x : y; }
void Pushup( int x ) { mn[x]=vmin(x,vmin(mn[lc],mn[rc])); }
void Pushdown( int x ) { if ( tag[x] ) { int tmp=lc; tag[lc=rc]^=1; tag[rc=tmp]^=1; tag[x]=0; } }
void Pushall( int x ) { if ( IsRoot(x) ) Pushall(f[x]); Pushdown(x); }
void Rotate( int x ) 
{
    int y=f[x],z=f[y],kid=tr[y][1]==x,oth=tr[x][!kid];
    if ( IsRoot(y) ) tr[z][tr[z][1]==y]=x;
    tr[x][!kid]=y; tr[y][kid]=oth; f[oth]=y; f[y]=x; f[x]=z;
    Pushup(y);
}
void Splay( int x )
{
    int y=x; Pushall(x);
    while ( IsRoot(x) )
    {
        if ( IsRoot(y=f[x]) ) Rotate( (tr[y][0]==x)^(tr[f[y]][0]==y) ? x : y );
        Rotate(x);
    }
    Pushup(x);
}
void Access( int x ) { for ( int y=0; x; x=f[y=x] ) Splay(x),rc=y,Pushup(x); }
void MakeRoot( int x ) { Access(x); Splay(x); tag[x]^=1; }
void Link( int i ) { MakeRoot(e[i].fro); f[f[e[i].fro]=N+i]=e[i].to; }
void Cut( int x ) { Access(e[x-N].fro); Splay(x); lc=rc=f[lc]=f[rc]=0; }
int Find( int x ) { return x==fa[x] ? x : fa[x]=Find(fa[x]); }

int main()
{
    n=read(); m=read();
    for ( int i=0; i<=n; i++ ) fa[i]=i,val[i]=INF;
    for ( int i=1; i<=m; i++ ) e[i].fro=read(),e[i].to=read(),e[i].len=read();

    sort( e+1,e+1+m ); int cnt=1,pt=1,x,y;
    for ( int i=1; i<=m; i++ )
    {
        val[i+N]=e[i].len;
        if ( Find(x=e[i].fro)^Find(y=e[i].to) )
        {
            vis[i]=1; Link(i); fa[fa[x]]=fa[y]; cnt++;
            if ( cnt==n ) ans=e[i].len-e[pt].len;
        }
        else
        {
            if ( x==y ) continue;
            vis[i]=1; MakeRoot(x); Access(y); Splay(y); vis[mn[y]-N]=0; 
            while ( !vis[pt] ) pt++;
            Cut(mn[y]); Link(i);
            if ( cnt==n ) bmin( ans,e[i].len-e[pt].len );
        }
    }
    printf( "%d\n",ans );
    return 0;
}
LCT维护子树
//Author:RingweEH
//P4219 [BJOI2014]大融合
#define lc tr[x][0]
#define rc tr[x][1]
const int N=1e5+10;
int fa[N],tr[N][2],s[N],si[N],n,m;
bool tag[N];
bool IsRoot( int x ) { return (tr[fa[x]][0]==x) || (tr[fa[x]][1]==x); }	
void Pushup( int x ) { s[x]=s[lc]+s[rc]+si[x]+1; }
void Pushdown( int x )	{ if ( tag[x] ) { int tmp=lc; lc=rc; rc=tmp; tag[lc]^=1; tag[rc]^=1; tag[x]=0; } }
void Pushall( int x ) { if ( IsRoot(x) ) Pushall(fa[x]); Pushdown(x); }
void Rotate( int x ) 
{
    int y=fa[x],z=fa[y],kid=tr[y][1]==x,oth=tr[x][!kid];
    if ( IsRoot(y) ) tr[z][tr[z][1]==y]=x;
    tr[x][!kid]=y; tr[y][kid]=oth; fa[oth]=y; fa[y]=x; fa[x]=z;
    Pushup(y);
}
void Splay( int x )
{
    int y=x; Pushall(x);
    while ( IsRoot(x) )
    {
        if ( IsRoot(y=fa[x]) ) Rotate( (tr[y][0]==x)^(tr[fa[y]][0]==y) ? x : y );
        Rotate(x);
    }
    Pushup(x);
}
void Access( int x ) { for ( int y=0; x; x=fa[y=x] ) Splay(x),si[x]+=s[rc],si[x]-=s[rc=y]; } 
void MakeRoot( int x ) { Access(x); Splay(x); tag[x]^=1; }	 
void Split( int x,int y ) { MakeRoot(x); Access(y); Splay(y); }	
void Link( int x,int y ) { Split(x,y); si[fa[x]=y]+=s[x]; Pushup(y); } 

int main()
{
	n=read(); m=read();
	for ( int i=1; i<=n; i++ ) s[i]=1;
	while ( m-- )
	{
		char opt[5]; scanf( "%s",opt ); int x=read(),y=read();
		if ( opt[0]=='A' ) Link(x,y);
		else Split(x,y),printf("%lld\n",1ll*(si[x]+1)*(si[y]+1) );
	}

	return 0;
}

莫队

普通莫队
//Author:RingweEH
//SP3267 DQUERY - D-query
const int N=3e5,Q=2e5+10,C=1e6+10;
int n,a[N],cnt[C],num,bel[N],siz,bnum,ans[Q];

struct Node
{
	int l,r,id;
	bool operator < ( Node tmp ) const  
	{ return (bel[l]^bel[tmp.l]) ? (bel[l]<bel[tmp.l]) : ((bel[l]&1) ? r<tmp.r : r>tmp.r);  }
}Que[Q];

void Init()
{
	siz=sqrt(n); bnum=ceil((double)n/siz);
	for ( int i=1; i<=bnum; i++ )
		for ( int j=(i-1)*siz+1; j<=i*siz; j++ )
			bel[j]=i;
}

void Del( int x ) { cnt[a[x]]--; num-=(cnt[a[x]]==0); }
void Add( int x ) { cnt[a[x]]++; num+=(cnt[a[x]]==1); }

int main()
{
	n=read(); Init();
	for ( int i=1; i<=n; i++ ) a[i]=read();
	int q=read();
	for ( int i=1; i<=q; i++ )
		Que[i].l=read(),Que[i].r=read(),Que[i].id=i;

	sort( Que+1,Que+1+q );
	int l=1,r=0;
	for ( int i=1; i<=q; i++ )
	{
		int ql=Que[i].l,qr=Que[i].r;
		while ( l<ql ) Del(l),l++;
		while ( l>ql ) l--,Add(l);
		while ( r<qr ) r++,Add(r);
		while ( r>qr ) Del(r),r--;
		ans[Que[i].id]=num;
	}

	for ( int i=1; i<=q; i++ )
		printf( "%d\n",ans[i] );

	return 0;
}
带修莫队
//Author:RingweEH
const int N=133333*2+10,C=1000010;
int a[N],cnt[C],ans[N],bel[N],n,m,cntq=0,cntc=0;
struct Queries
{
    int l,r,tim,id;
    bool operator < ( Queries tmp )
    {
        if ( bel[l]^bel[tmp.l] ) return bel[l]<bel[tmp.l];
        if ( bel[r]^bel[tmp.r] ) return bel[r]<bel[tmp.r];
        return (bel[l]&1) ? tim<tmp.tim : tim>tmp.tim;
    }
}Que[N];
struct Crayon
{
    int pos,col,las;
}c[N];

void Init()
{
    int siz=pow(n,2.0/3.0),bnum=ceil((double)n/siz);
    for ( int i=1,tmp=min(n,i*siz); i<=bnum; i++,tmp=min(n,i*siz) )
        for ( int j=(i-1)*siz+1; j<=tmp; j++ )
            bel[j]=i;
}

int main()
{
    n=read(); m=read();
    for ( int i=1; i<=n; i++ ) a[i]=read();
    for ( int i=1; i<=m; i++ )
    {
        char opt[5]; scanf( "%s",opt );
        if ( opt[0]=='Q' )
        {
            cntq++; Que[cntq].l=read(),Que[cntq].r=read();
            Que[cntq].tim=cntc; Que[cntq].id=cntq;
        }
        else cntc++,c[cntc].pos=read(),c[cntc].col=read();
    }

    Init(); sort( Que+1,Que+cntq+1 );
    int l=1,r=0,tim=0,res=0;
    for ( int i=1; i<=cntq; i++ )
    {
        int ql=Que[i].l,qr=Que[i].r,qt=Que[i].tim;
        while ( l<ql ) res-=!--cnt[a[l++]];
        while ( l>ql ) res+=!cnt[a[--l]]++;
        while ( r<qr ) res+=!cnt[a[++r]]++;
        while ( r>qr ) res-=!--cnt[a[r--]];
        while ( tim<qt )
        {
            ++tim;
            if ( ql<=c[tim].pos && c[tim].pos<=qr ) 
                res-=!--cnt[a[c[tim].pos]] - !cnt[c[tim].col]++;
            swap( a[c[tim].pos],c[tim].col );
        }
        while ( tim>qt )
        {
            if ( ql<=c[tim].pos && c[tim].pos<=qr ) 
                res-=!--cnt[a[c[tim].pos]] - !cnt[c[tim].col]++;
            swap( a[c[tim].pos],c[tim].col );
            --tim;
        }
        ans[Que[i].id]=res;
    }

    for ( int i=1; i<=cntq; i++ )
        printf( "%d\n",ans[i] );
}
树上莫队
//Author:RingweEH
//SPOJ10707 Count on a tree II
const int N=2e5+1000;
int a[N],cnt[N],fir[N],las[N],bel[N],tmp[N],vis[N],ncnt,ans[N],nw=0;
int ord[N],val[N],head[N],dep[N],fa[N][30],tot=0,n,m;
struct Queries
{
    int l,r,lca,id;
    bool operator < ( Queries tt )
    { return (bel[l]^bel[tt.l]) ? bel[l]<bel[tt.l] : ((bel[l]&1) ? r<tt.r : r>tt.r); }
}q[N];
struct Edge { int to,nxt; }e[N];
void Adde( int u,int v ) { e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; }

void DFS( int x )
{
    ord[++ncnt]=x; fir[x]=ncnt; 
    for ( int i=head[x]; i; i=e[i].nxt )
    {
        int y=e[i].to;
        if ( y==fa[x][0] ) continue;
        dep[y]=dep[x]+1; fa[y][0]=x;
        for ( int i=1; (1<<i)<=dep[y]; i++ )
            fa[y][i]=fa[fa[y][i-1]][i-1];
        DFS( y );
    }
    ord[++ncnt]=x; las[x]=ncnt;
}

int Get_LCA( int u,int v )
{
    if ( dep[u]<dep[v] ) swap( u,v );
    for ( int i=20; i+1; i-- )
        if ( dep[fa[u][i]]>=dep[v] ) u=fa[u][i];
    if ( u==v ) return u;
    for ( int i=20; i+1; i-- )
        if ( fa[u][i]!=fa[v][i] ) u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}

void Addel( int pos )
{
	vis[pos] ? nw-=!--cnt[val[pos]] : nw+=!cnt[val[pos]]++;
    vis[pos]^=1;
}

void Init()
{
    sort( tmp+1,tmp+n+1 );
    int tot1=unique( tmp+1,tmp+1+n )-tmp-1;
    for ( int i=1; i<=n; i++ )
        val[i]=lower_bound( tmp+1,tmp+tot1+1,val[i] )-tmp;
}

int main()
{
	n=read(); m=read();
	for ( int i=1; i<=n; i++ ) val[i]=read(),tmp[i]=val[i];
	for ( int i=1,u,v; i<n; i++ ) u=read(),v=read(),Adde( u,v ),Adde( v,u );
    Init(); dep[1]=1; DFS( 1 );
    int siz=sqrt( ncnt ),bnum=ceil((double)ncnt/siz);
    for ( int i=1; i<=bnum; i++ )
        for ( int j=siz*(i-1)+1; j<=i*siz; j++ )
            bel[j]=i;

    for ( int i=1,l,r,lca; i<=m; i++ )
    {
        l=read(); r=read(); lca=Get_LCA( l,r );
        if ( fir[l]>fir[r] ) swap( l,r );
        if ( l==lca ) q[i].l=fir[l],q[i].r=fir[r];
        else q[i].l=las[l],q[i].r=fir[r],q[i].lca=lca;
        q[i].id=i;
    }
    int l=1,r=0; sort( q+1,q+1+m );
    for ( int i=1; i<=m; i++ )
    {
        int ql=q[i].l,qr=q[i].r,lca=q[i].lca;
        while ( l<ql ) Addel( ord[l++] );
        while ( l>ql ) Addel( ord[--l] );
        while ( r<qr ) Addel( ord[++r] );
        while ( r>qr ) Addel( ord[r--] );
        if ( lca ) Addel( lca );
        ans[q[i].id]=nw;
        if ( lca ) Addel( lca );
    }
    for ( int i=1; i<=m; i++ )
        printf( "%d\n",ans[i] );

    return 0;
}
回滚莫队
//Author:RingweEH
//AT JOISC 2014 C - 歴史の研究
const int N=1e5+10;
int a[N],b[N],tmp[N],n,m;
int cnt[N],cnt2[N],bel[N],lb[N],rb[N],bnum;
ll ans[N];
struct Queries
{
	int l,r,id;
	bool operator < ( Queries tmp ) { return (bel[l]^bel[tmp.l]) ? bel[l]<bel[tmp.l] : r<tmp.r; }
}q[N];

void Init()
{
	int siz=sqrt(n); bnum=ceil((double)n/siz);
	for ( int i=1; i<=bnum; i++ )
	{
		lb[i]=siz*(i-1)+1; rb[i]=min(n,siz*i);
		for ( int j=lb[i]; j<=rb[i]; j++ ) bel[j]=i;
	}
	sort( tmp+1,tmp+1+n ); int tot=unique(tmp+1,tmp+1+n)-tmp-1;
	for ( int i=1; i<=n; i++ )
		b[i]=lower_bound( tmp+1,tmp+1+tot,a[i] )-tmp;
	sort( q+1,q+1+m );
}

int main()
{
	n=read(); m=read(); Init();
	for ( int i=1; i<=n; i++ ) a[i]=read(),tmp[i]=a[i];
	for ( int i=1; i<=m; i++ ) q[i].l=read(),q[i].r=read(),q[i].id=i;
	
	Init();	int pos=1,l,r,ql,qr,qid; ll nw=0,tt;
	for ( int k=1; k<=bnum; k++ )
	{
		l=rb[k]+1; r=rb[k]; nw=0; memset( cnt,0,sizeof(cnt) );
		for ( ; bel[q[pos].l]==k; pos++ )
		{
			ql=q[pos].l; qr=q[pos].r; qid=q[pos].id;
			if ( bel[ql]==bel[qr] )
			{
				tt=0;
				for ( int j=ql; j<=qr; j++ ) cnt2[b[j]]=0;
				for ( int j=ql; j<=qr; j++ )
					cnt2[b[j]]++,bmax( tt,1ll*cnt2[b[j]]*a[j] );
				ans[qid]=tt; continue;
			}
			while ( r<qr ) ++cnt[b[++r]],bmax(nw,1ll*cnt[b[r]]*a[r]);
			tt=nw;
			while ( l>ql ) ++cnt[b[--l]],bmax(nw,1ll*cnt[b[l]]*a[l]);
			ans[qid]=nw;
			while ( l<rb[k]+1 ) --cnt[b[l++]];
			nw=tt;
		}
	}

	for ( int i=1; i<=m; i++ ) printf( "%lld\n",ans[i] );

	return 0;
}
二次离线莫队
//Author:RingweEH
//【模板】莫队二次离线(第十四分块(前体))
const int N=1e5+10;
int bel[N],a[N],n,m,k,cnt[N],pre[N];
struct Queries
{
    int l,r,id; ll ans;
    bool operator < ( Queries tmp ) { return (bel[l]^bel[tmp.l]) ? l<tmp.l : r<tmp.r; }
}q[N];
struct Node 
{ 
    int x,y,pos; 
    Node ( int _x=0,int _y=0,int _pos=0 ) : x(_x),y(_y),pos(_pos) {}
};
vector<Node> opt[N];
vector<int> buc;
ll ans[N];

#define lowbit(x) ((x)&(-x))
int Count( int x ) { int res=0; for ( ; x; x-=lowbit(x) ) res++; return res; }
void Init()
{
    for ( int i=0; i<16384; i++ ) 
        if ( Count(i)==k ) buc.push_back(i);
    int siz=sqrt(n);
    for ( int i=1; i<=n; i++ ) bel[i]=(i-1)/siz+1;
    sort( q+1,q+1+m ); memset( cnt,0,sizeof(cnt) );
    for ( int i=1; i<=n; i++ )
    {
        for ( auto x : buc ) cnt[a[i]^x]++;
        pre[i]=cnt[a[i+1]]; //记住你计算的前缀多了1!
    }
}

int main()
{
    n=read(); m=read(); k=read();
    if ( k>14 ) { for ( int i=1; i<=m; i++ ) printf( "0\n" ); return 0; }
    for ( int i=1; i<=n; i++ ) a[i]=read();
    for ( int i=1; i<=m; i++ ) q[i].l=read(),q[i].r=read(),q[i].id=i;

    Init(); int l=1,r=0,ql,qr,qid; memset( cnt,0,sizeof(cnt) );
    for ( int i=1; i<=m; i++ )
    {
        ql=q[i].l; qr=q[i].r;
        //相当于是r不动,计算固定右端点对区间变化的贡献,l同理
        if ( l<ql ) opt[r].push_back( Node(l,ql-1,-i) );  //记录第二类贡献的标记
        while ( l<ql ) q[i].ans+=pre[l-1],l++;    //累计第一类的贡献
        if ( l>ql ) opt[r].push_back( Node(ql,l-1,i) );
        while ( l>ql ) q[i].ans-=pre[l-2],l--;
        if ( r<qr ) opt[l-1].push_back( Node(r+1,qr,-i) );
        while ( r<qr ) q[i].ans+=pre[r],r++;
        if ( r>qr ) opt[l-1].push_back( Node(qr+1,r,i) );
        while ( r>qr ) q[i].ans-=pre[r-1],r--;
    }
    for ( int i=1; i<=n; i++ )      //计算 a[1~i] 对所有后面的区间的贡献,暴力统计
    {
        for ( auto x : buc ) cnt[a[i]^x]++;
        for ( int j=0; j<opt[i].size(); j++ )
        {
            l=opt[i][j].x; r=opt[i][j].y; qid=opt[i][j].pos;
            for ( int j=l,tmp; j<=r; j++ )
            {
                tmp=cnt[a[j]]; tmp-=(j<=i && k==0);
                (qid<0) ? q[-qid].ans-=tmp : q[qid].ans+=tmp;
            }
        }
    }
    for ( int i=1; i<=m; i++ ) q[i].ans+=q[i-1].ans;
    for ( int i=1; i<=m; i++ ) ans[q[i].id]=q[i].ans;
    for ( int i=1; i<=m; i++ ) printf( "%lld\n",ans[i] );
    return 0;
}
posted @ 2020-11-12 13:57  MontesquieuE  阅读(27)  评论(0编辑  收藏  举报