【模板】数据结构

一般用法:默一遍,提交代码,AC才过关

LCT https://www.luogu.com.cn/problem/P1501
重点:f[x]=c[y][0]=0;

#include<bits/stdc++.h>
#define R register unsigned int
#define I inline void
#define lc c[x][0]
#define rc c[x][1]
using namespace std;
const int N=1e5+10,mod=51061;
unsigned int f[N],c[N][2],val[N],s[N],sta[N],size[N],la[N],lm[N],top;
bool r[N];
int in(){
	char c=getchar();  int op=0; 
	while(!isdigit(c)) c=getchar(); 
	while(isdigit(c)) op=op*10+c-'0',c=getchar();
	return op; 
}
inline bool isroot(R x) { return (c[f[x]][0]!=x && c[f[x]][1]!=x); }
inline bool son(int x) { return x==c[f[x]][1]; }//判左右朝向 

I update(R x)  { s[x]=(s[lc]+s[rc]+val[x])%mod; size[x]=size[lc]+size[rc]+1; }
I reverse(R x) { if(x) swap(lc,rc),r[x]^=1; }
I add(R x,R k) { s[x]=(s[x]+k*size[x])%mod;   val[x]=(val[x]+k)%mod; la[x]=(la[x]+k)%mod; }
I mul(R x,R k) { s[x]=s[x]*k%mod; la[x]=la[x]*k%mod; val[x]=val[x]*k%mod; lm[x]=lm[x]*k%mod; }
I pushdown(R x){ 
	if(lm[x]!=1)mul(lc,lm[x]),mul(rc,lm[x]),lm[x]=1;
    if(la[x])   add(lc,la[x]),add(rc,la[x]),la[x]=0;
	if(r[x])    reverse(lc),reverse(rc),r[x]=0; 
}
I rotate(R x){
	int y=f[x],z=f[y];
	if(!isroot(y)) c[z][son(y)]=x;//有爷爷就要更新  //x代替y 
	int a=son(x),w=c[x][!a];//我是y的左儿子,我的右儿子(反儿子、另一个儿子)变成y的左儿子 
	f[w]=y; c[y][a]=w;//x的另一个儿子代替x原来的位置 
	f[y]=x; c[x][!a]=y;
	f[x]=z; update(y);
}
I splay(R x){
	sta[top=1]=x;
	for(R i=x;!isroot(i);i=f[i]) sta[++top]=f[i];
	while(top) pushdown(sta[top--]);
	for(R y=f[x];!isroot(x);rotate(x),y=f[x])
		if(!isroot(y)) rotate(son(x)^son(y)?x:y); 
	update(x);
}
I access(R x)	 {for(R y=0;x;x=f[y=x])splay(x),rc=y,update(x);}
I makeroot(R x)  {access(x);splay(x);reverse(x);}
I split(R x,R y) {makeroot(x);access(y);splay(y);}//将路径提到splay里 
I link(R x,R y)  {makeroot(x);f[x]=y;}
I cut(R x,R y)   {split(x,y);f[x]=c[y][0]=0;}//y旋成根,x为y左儿子,所以左儿子变0 
int main()
{
	R n=in(),q=in(),x,y,c;
	for(R i=1;i<=n;++i) val[i]=size[i]=lm[i]=1;
	for(R i=1;i<n;i++) x=in(),y=in(),link(x,y);
	while(q--){
		char p[10];scanf("%s",p);
		if(p[0]=='+'){
			x=in(),y=in(),c=in();
			split(x,y),add(y,c);
		}
		if(p[0]=='-'){
			x=in(),y=in();cut(x,y);
			x=in(),y=in();link(x,y);
		}
		if(p[0]=='*'){
			x=in(),y=in(),c=in();
			split(x,y),mul(y,c);
		}
		if(p[0]=='/'){
			x=in(),y=in();
			split(x,y),printf("%d\n",s[y]);
		}
	}
	return 0;
}
树链剖分 改段  https://www.luogu.com.cn/problem/P2486#submit
重点:dep[top[x]]<dep[top[y]] 如果用tx ty 要 swap(x,y) swap(tx,ty)

#include<cstdio>
#include<cstring>
#define LL long long
#include<algorithm>
using namespace std;
const int N=100010;
int n,len=0,first[N];
struct bian{int y,gg;}b[N<<1];
void ins(int x,int y){
	b[++len].y=y;
	b[len].gg=first[x];
	first[x]=len;
}
int dep[N],tot[N],son[N],fa[N];
void dfs(int x){
	dep[x]=dep[fa[x]]+1; tot[x]=1;
	for(int i=first[x];i>0;i=b[i].gg){
		int y=b[i].y;
		if(y!=fa[x]){
			fa[y]=x;dfs(y);
			if(!son[x] || tot[y]>tot[son[x]]) son[x]=y; tot[x]+=tot[y];
		}
	}
}
int fre[N],rev[N],top[N],trlen=0;
void dfs2(int x,int tp){
	fre[x]=++trlen;  top[x]=tp;
	if(son[x]) dfs2(son[x],tp);
	for(int i=first[x];i>0;i=b[i].gg){
		int y=b[i].y; 
		if(y!=fa[x] && y!=son[x])	dfs2(y,y);
	}	
}//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM//MMM
struct tree{int c,l,r,lz;}tr[N<<2];
void pushdown(int now){
	if(tr[now].lz){
		tr[now<<1].lz=tr[now<<1|1].lz=
		tr[now<<1].l=tr[now<<1|1].l=
		tr[now<<1].r=tr[now<<1|1].r=tr[now].lz;
		tr[now<<1].c=tr[now<<1|1].c=1;
		tr[now].lz=0;
	}
}
void update(int now){
	tr[now].c=tr[now<<1].c+tr[now<<1|1].c;
  	if(tr[now<<1].r && tr[now<<1|1].l && tr[now<<1].r==tr[now<<1|1].l) tr[now].c--;
  	tr[now].l=tr[now<<1].l;
	tr[now].r=tr[now<<1|1].r;
}
void chan(int now,int l,int r,int x,int k)
{
	if(l==r){
		tr[now].l=tr[now].r=k;
		tr[now].c=1;
//		if(l==4) printf("%d",now);
	    return;
	}
	int mid=(l+r)>>1;
   	if(x<=mid) chan(now<<1,l,mid,x,k);
  	else chan(now<<1|1,mid+1,r,x,k);
  	update(now);
	//printf("c=%d l%d r%d now%d\n",tr[now].c,tr[now].l,tr[now].r,now) ;
}
void change(int now,int l,int r,int L,int R,int k)
{
	if(l>R || r<L) return ;
	if(L<=l && r<=R){
		tr[now].lz=tr[now].l=tr[now].r=k;
		tr[now].c=1;
	    return;
	}
	int mid=(l+r)>>1;
	pushdown(now);
   	change(now<<1,l,mid,L,R,k);
  	change(now<<1|1,mid+1,r,L,R,k);
  	update(now);
}
int dL,dR;
int minn(int x,int y ){ return x<y?x:y; }  
int maxx(int x,int y ){ return x>y?x:y; }  
int find(int now,int l,int r,int L,int R)
{	 
//	printf("%d %d %d %d %d\n",now,l,r,L,R);
	if(l==L) dL=tr[now].l;
	if(r==R) dR=tr[now].r;
	if(l>R || r<L) return 0;
	if(L<=l && r<=R) {/*printf("\nn=%d %d\n",now,tr[now].c);*/return tr[now].c;}
	int mid=(l+r)>>1;
	pushdown(now);
	int ll=find(now<<1,l,mid,L,R), rr=find(now<<1|1,mid+1,r,L,R);
   	return ll + rr + ((ll && rr && tr[now<<1].r==tr[now<<1|1].l)?-1:0); /*重中之重*/
}//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM/
int fsolve(int x,int y)
{
	int tx=top[x],ty=top[y],ans=0;
	int la1=-1,la2=-1;
	while(tx!=ty)
	{
		if(dep[tx]>dep[ty]) swap(tx,ty),swap(x,y),swap(la1,la2);
	//	printf("%d %d %d\n",fre[ty],fre[y],y);
		dL=2147483647,dR=0;
		ans+=find(1,1,trlen,fre[ty],fre[y]);
		if(la2==dR) ans--;
		la2=dL;
		y=fa[ty];ty=top[y];
	}
	if(dep[x]>dep[y]) swap(x,y),swap(la1,la2);
	dL=2147483647,dR=0;
	ans+=find(1,1,trlen,fre[x],fre[y]);
	if(dL==la1) ans--;
	if(dR==la2) ans--;
	return ans;
}
void csolve(int x,int y,int c)
{
	int tx=top[x],ty=top[y];
	while(tx!=ty)
	{
		if(dep[tx]>dep[ty]) swap(tx,ty),swap(x,y);
	//	printf("\nty%d y%d\n",ty,y);
		change(1,1,trlen,fre[ty],fre[y],c);
		y=fa[ty];ty=top[y];
	}
	if(dep[x]>dep[y]) swap(x,y);
	change(1,1,trlen,fre[x],fre[y],c);
}//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM/
int a[N],m;
int main(){
	scanf("%d %d",&n,&m);
	int x,y,c;
	for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
	for(int i=1;i<n;i++){
		scanf("%d %d",&x,&y);
		ins(x,y);ins(y,x);
	}
	dfs(1);dfs2(1,1);	
	for(int i=1;i<=n;i++)  chan(1,1,trlen,fre[i],a[i]);
	
	char p[20]; 
	for(int i=1;i<=m;i++){//printf("\n\n\n\n\n");
		scanf("%s %d %d",p+1,&x,&y);
		if(p[1]=='C') scanf("%d",&c),csolve(x,y,c);
		else if(p[1]=='Q') printf("%d\n",fsolve(x,y));
	}
	return 0;
}
lca  https://www.luogu.com.cn/problem/P3379
重点: f[x][i]!=f[y][i] 而不是 dep[f[x][i]]!=dep[f[y][i]]

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=500100;
int x[N],y[N],w[N];
struct node{int x,y,c;}a[N<<1];
bool cmp(node a,node b) { return a.c<b.c; }
bool v[N];
int len=0,first[N];
struct bian{int y,c,gg;}b[N<<1];

void ins(int x,int y){
	b[++len].y=y;
//	b[len].c=c;
	b[len].gg=first[x];
	first[x]=len;
}
int f[N][22],dep[N],m[N][22];
int maxx(int x,int y){ return x>y?x:y; }
void dfs(int x)
{
	dep[x]=dep[f[x][0]]+1;
	for(int i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];//, M[x][i]=max(M[x][i-1],M[f[x][i-1]][i-1]);
	for(int i=first[x];i>0;i=b[i].gg){
		int y=b[i].y;
		if(y!=f[x][0]){
			f[y][0]=x;//M[x][0]=b[i].c;
			dfs(y);
		}
	}
}
int l[N],R[N];
int lca(int x,int y){
	int ans=0;	
	if(dep[x]>dep[y]) swap(x,y);
	for(int i=20;i>=0;i--) if(dep[f[y][i]]>=dep[x]) /*ans=maxx(ans,m[y][i]),*/ y=f[y][i];
	if(x==y) return x;//return ans;
	for(int i=20;i>=0;i--) if(f[y][i]!=f[x][i]) 
	/*ans=maxx(ans,m[y][i]),ans=maxx(ans,m[x][i]),*/y=f[y][i],x=f[x][i];
	//ans=maxx(ans,m[x][0]),ans=maxx(ans,m[y][0]);return ans;
	return f[x][0]; 
}
int main()
{
	int n,Q,st,x,y,c;scanf("%d %d %d",&n,&Q,&st);
	for(int i=1;i<n;i++) scanf("%d %d",&x,&y),ins(x,y),ins(y,x);
	dfs(st);
	for(int i=1;i<=Q;i++){
		scanf("%d %d",&x,&y);
		printf("%d\n",lca(x,y));
	}
	return 0;
}

扫描线计算面积 https://www.luogu.com.cn/problem/P5490
左闭右开为了处理a[r]-a[r]=0 
看这样两条相邻线段:[1,2],[2,3]
你会发现[1,2][2,3]={2},也就是说左儿子的右端点和右儿子的左端点其实是重合的。
所以右端点手动减1,计算时再用r+1计算 

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
LL n;
LL X1[100100], Y1[100100], X2[100100], Y2[100100];
struct TR{
	LL X,Y1,Y2,k;
	TR(LL X=0,LL Y1=0,LL Y2=0,LL k=0) : X(X),Y1(Y1),Y2(Y2),k(k) { }
}line[200100];
bool cmp(TR a, TR b) { return a.X<b.X; }
long long tag[900100];
long long tree[900100],a[200100];
void push_down(LL now, LL l, LL r){
    if(tag[now]) tree[now]=a[r+1]-a[l];//左闭右开
	else tree[now]=tree[now<<1] + tree[now<<1|1];
}
void add(LL now,LL l,LL r,LL L,LL R,LL k) {//维护一个区间加,区间为正个数 
  	if(R<l || r<L) return ; 
    if(L<=l && r<=R) {
        tag[now]+=k;
        push_down(now,l,r);
        return ;
    }
    LL mid=(l+r)>>1;
    add(now<<1, l,mid, L,R,k);
	add(now<<1|1, mid+1,r, L,R,k);
    push_down(now,l,r);
}
int main() {
    scanf("%lld", &n);
    LL tot=0;
   	for(LL i=1;i<=n;i++){
        scanf("%lld %lld %lld %lld",&X1[i],&Y1[i],&X2[i],&Y2[i]);
        a[++tot]=Y1[i];
        line[tot]=TR(X1[i],Y1[i],Y2[i],1);//水平扫过去,到了这个左端加一排 
        a[++tot]=Y2[i];
        line[tot]=TR(X2[i],Y1[i],Y2[i],-1);//到了右端减一排 
    }
    sort(a+1,a+1+tot);
    sort(line+1,line+1+tot,cmp);
    LL m=unique(a+1,a+1+tot)-(a+1);
    long long ans=0;
    for(LL i=1;i<tot;i++) {
        LL L=lower_bound(a+1, a+1+m, line[i].Y1) - a;
        LL R=lower_bound(a+1, a+1+m, line[i].Y2) - a -1;///左闭右开
		if(L<=R) add(1,1,m,L,R,line[i].k);
        ans+=tree[1]*(line[i+1].X-line[i].X);//计算面积 
    }
    printf("%lld\n", ans);
    return 0;
}
三维偏序 排序+CDQ分治(归并版)+树状数组 https://www.luogu.com.cn/problem/P3810

#include<cstdio>
#include<algorithm>
#define I inline  
#define R register int
using namespace std;
const int N=1e5+10;
int n,m;
int val[N],ans[N],cnt[N],tr[N<<1];
struct node{int a,b,c,p;}a[N],p[N],q[N];
I int lowbit(R x)     { return x&(-x); }
I int ask(R i)        { R v=0; for(;i;i-=lowbit(i)) v+=tr[i]; return v; }
I void change(R i,R v){ for(;i<=m;i+=lowbit(i)) tr[i]+=v; }
I void cdq(int l,int r)
{
	if(l==r) return;
	int mid=(l+r)>>1,i=l,j=mid+1;
	cdq(l,mid),cdq(mid+1,r);
	for(int k=l;k<=r;k++){
		if((i<=mid && p[i].b<=p[j].b) || j>r) change(p[i].c,val[p[i].p]),q[k]=p[i++];
		else cnt[p[j].p]+=ask(p[j].c),q[k]=p[j++];
	}
	for(int i=l;i<=mid;i++) change(p[i].c,-val[p[i].p]);
	for(int i=l;i<=r;i++) p[i]=q[i];
}
inline bool cmp(node x,node y){
	if(x.a==y.a){if(x.b==y.b) return x.c<y.c; else return x.b<y.b;}
	else return x.a<y.a;
}
int main()
{
	int tn;scanf("%d %d",&tn,&m);
	for(int i=1;i<=tn;i++)
		scanf("%d %d %d",&a[i].a,&a[i].b,&a[i].c);
	sort(a+1,a+tn+1,cmp); n=0;
	for(int i=1;i<=tn;i++){//去重 
		if(a[i].a^a[i-1].a || a[i].b^a[i-1].b || a[i].c^a[i-1].c) p[++n]=a[i],p[n].p=n;
		val[n]++;								
	}
	cdq(1,n);
	for(int i=1;i<=n;i++)
		ans[cnt[p[i].p]+val[p[i].p]-1]+=val[p[i].p];
	for(int i=0;i<tn;i++) printf("%d\n",ans[i]);
	return 0;
}
主席树 静态区间第k小 https://www.luogu.com.cn/problem/P3834#submit

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
int b[200100],c[200100],trlen=0;
struct node{int id,c;}a[200100];
struct tree{int lc,rc,c;}tr[4000100];//主席树本身 
int root[200100];//维护前i个数有几个在当前值域内 
int bt(int l,int r)//同时掌控搜索区间
{
	int p=++trlen;
	if(l==r) return p;
	int mid=(l+r)>>1;
	tr[p].lc=bt(l,mid); tr[p].rc=bt(mid+1,r);
	return p;
}
int insert(int now,int l,int r,int x)
{
	int p=++trlen;
	tr[p]=tr[now];tr[p].c++;
	if(l==r) return p; 
	int mid=(l+r)>>1;
	if(x<=mid)  tr[p].lc=insert(tr[now].lc,l,mid,x);
	else  		tr[p].rc=insert(tr[now].rc,mid+1,r,x);
	return p;
}
int find(int x,int y,int l, int r,int k)
{
	if(l==r) return l;
	int cnt=tr[tr[y].lc].c-tr[tr[x].lc].c;
	//root[y]:插入1~y root[x]:插入1~x 相减显然是对应值域编号x~y 在此值域的个数
	int mid=(l+r)>>1;
	if(k<=cnt) return find(tr[x].lc,tr[y].lc,l,mid,k);
	else return find(tr[x].rc,tr[y].rc,mid+1,r,k-cnt);
}
bool cmp(node a,node b) { return a.c<b.c; }
int main()
{
	int n,m,len=0;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].c),a[i].id=i;
	sort(a+1,a+1+n,cmp);
	b[a[1].id]=++len;c[len]=a[1].c;
	for(int i=2;i<=n;i++) {//去重 +离散化
		if(a[i].c!=a[i-1].c) c[++len]=a[i].c;
		b[a[i].id]=len;
	}
	root[0]=bt(1,len);
	for(int i=1;i<=n;i++)
	root[i]=insert(root[i-1],1,len,b[i]);
	int x,y,k;
	for(int i=1;i<=m;i++){
		scanf("%d %d %d",&x,&y,&k);
		printf("%d\n",c[find(root[x-1],root[y],1,len,k)]); 
	}
	return 0;
}
普通莫队
背板子重点:
1.分块按照n−−√sqrt{n} 
2.不必按块枚举,询问区间属于哪一块的信息记录在结构体内排序
3.排序先按块升序,再按右端点升序
4. l=1,r=0 防止(1,1)无法记录,所以r=0

#include<cstdio>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
int a[51000],t[51000];//t[i]数i出现次数 
struct node{int x,y,i,d;}st[51000]; //区间左右范围 ;属于哪个块   最大50000^2 25亿->long long 
bool cmp(node a,node b) 
{
	if(a.d==b.d)  return a.y<b.y;
	return a.d<b.d;
}LL ans=0,an[51000];
int main()
{
	int n,m,k;
	scanf("%d %d %d",&n,&m,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	int q=sqrt(n); 
	for(int i=1;i<=m;i++){
		scanf("%d %d",&st[i].x,&st[i].y);
		st[i].i=i, st[i].d= (st[i].x-1)/q + 1; //分块 
	}
	sort(st+1,st+1+m,cmp);	
	int l=1,r=0; //防止1 1无法记录,所以r=0  
	for(int i=1;i<=m;i++)
	{//直接左右端点移动即可,已经按排最坏n*sqrt(n)顺序 
		//左端点最多  m* sqrt(n)  ,右端点每块最多移到低(即n) sqrt(n)*n 
		while(l>st[i].x) l--, t[a[l]]++, ans+=2*t[a[l]]-1;  //(x)^2-(x-1)^2 =2*x-1
        while(r<st[i].y) r++, t[a[r]]++, ans+=2*t[a[r]]-1;
        while(l<st[i].x) t[a[l]]--, ans-=2*t[a[l]]+1, l++;
        while(r>st[i].y) t[a[r]]--, ans-=2*t[a[r]]+1, r--;
        an[st[i].i]=ans;
	}for(int i=1;i<=m;i++) printf("%lld\n",an[i]);
	return 0;
}
并查集
int find(int x){
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
树套树

Splay

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值