【模板】数据结构
并查集
并查集
//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;
}
大地也该是从一片类似的光明中冒出来的。