三维偏序学习笔记

三维偏序

  1. 第一维,通过排序直接解决
  2. 第二维,通过归并排序处理
  3. 第三维,通过数据结构解决
void CDQ(int l,int r){
    if(l==r)return;
    int mid = l+r>>1,L=l,R=mid+1;
    CDQ(l,mid),CDQ(mid+1,r);
    for(int i=l;i<=r;++i){
        if(R>r || L>=l && a[L].x<=a[R].x){
            c[i] = a[L];
            bit.add(a[L++].y,1);
        }
        else{
            c[i] = a[R];
            ans += bit.query(a[R++].y);
        }
    }
    
}
void CDQ(int l,int r){
    if(l==r)return;
    int mid = l+r>>1,L=l,R=mid+1;
    CDQ(l,mid),CDQ(mid+1,r);
    sort(a+l,a+mid+1,cmp),sort(a+mid+1,a+r+1,cmp);
    for(int i=l;i<=r;++i){
        if(R>r || L>=l && a[L].x<=a[R].x)bit.add(a[L++].y,1);
        else ans += bit.query(a[R++].y);
    }
}
int main(){
    sort(a+1,a+n+1);
}

动态逆序对

加入一维时间,表示删除的时间

  1. 二维偏序求出逆序对的数量
  2. 每次统计出,删除的数字构成的逆序对数量

\(i<j,a_i>a_j,t_i<t_j\)

\(i>j,a_i<a_j,t_i<t_j\)

void CDQ(int l,int r){
    if(l==r)return;
    int mid = l+r>>1,L=l,R=mid+1;
    CDQ(l,mid),CDQ(mid+1,r);
    sort(a+l,a+mid+1,cmp),sort(a+mid+1,a+r+1,cmp);
    for(int i=l;i<=r;++i){
        if(R>r || L>=l && a[L].x<=a[R].x)bit.add(a[L++].y,1);
        else{
            ans[a[R].x] += L - i - bit.query(a[R].y)
            ++R;
        }
    }
    for(int i=l;i<=mid;++i)bit.add(a[i].y,-1);
    for(int i=l;i<=r;++i){
        if(R>r || L>=l && a[L].x>=a[R].x)bit.add(a[L++].y,1);
        else{
            ans[a[R].x] ++ bit.query(a[R].y);
            ++R;
        }
    }
    for(int i=l;i<=mid;++i)bit.add(a[i].y,-1);
}

CF762E

  • \(i<j\)

  • \(min(r_i,r_j)\ge |x_i-x_j|\)

  • \(|f_i-f_j|\le k\)

选择 \(r_i\) 从大到小排序

  • \(i<j\)

  • \(r_j\ge |x_i-x_j|\) -> \(r_j-x_j\le x_i\le r_j+x_j\)

  • \(f_j-k\le f_i\le f_j+k\)

第二维选择 \(f_i\) 从小到大排序,结合双指针处理

第三维选择 \(x_i\) 从小到大排序,区间查询

void CDQ(int l,int r){
    if(l==r)return ;
    int mid = l+r>>1,L=l,R=l-1;
    CDQ(l,mid),CDQ(mid+1,r);
    sort(a+l,a+mid+1,cmp),sort(a+mid+1,a+r+1,cmp);
    for(int i=mid+1;i<=R;++i){
        while(R<mid && a[R+1].f<=a[i].f+k)bit.add(a[++R].x,1);
        while(L>=R && a[L].f<a[i].f-k)bit.add(a[L++].x,-1);
        ans += bit.query(a[i].x-a[i].r,a[i].x+a[i].r);
    }
}
int main(){
    sort(a+1,a+n+1,cmp1);//r 从大到小排序
}
struct P{
    int r,x,y,opt;
}q[N*5];
int main(){
    for(int i=1;i<=n;++i){
        q[++cnt] = {r[i],x[i],f[i],0};
        q[++cnt] = {r[i],r[i]-x[i]-1,f[i]-k-1,1};
        q[++cnt] = {r[i],r[i]-x[i]-1,f[i]+k,2};
        q[++cnt] = {r[i],r[i]+x[i],f[i]-k-1,2};
        q[++cnt] = {r[i],r[i]+x[i],f[i]+k,1};
    }
    
}

loj2056 序列

\(dp_i = max(dp[j])+1,i>j,a_i\ge a_j\)

//用归并排序实现 dp
void CDQ(int l,int r){
    if(l==r)return void(tomax(dp[l],1));
    int mid = l+r>>1;
    CDQ(l,mid);
    for(int i=mid+1;i<=r;++i)
        b[i] = a[i];
   	sort(b+mid+1,b+r+1,cmp);
    for(int i=mid+1,L=l,mx = 0;i<=r;++i){
        while(L<=mid && b[i].c>=a[L].c)tomax(mx,dp[a[L++].id]);
       	tomax(dp[b[i].id],mx+1);
    }
    CDQ(mid+1,r);
    sort(a+l,a+r+1,cmp);
}

\(mx_i,mi_i\)

\(dp_i = max(dp[j])+1,i>j,mi_i\ge a_j,a_i\ge mx_j\)

void CDQ(int l,int r){
    if(l==r)return void(tomax(dp[l],1));
    int mid = l+r>>1;
    CDQ(l,mid);//左边 x=a[i],y=mx[i] 右边 x=mi[i],y=a[i]
    for(int i=mid+1;i<=r;++i)c[i] = b[i];
    sort(c+mid+1,c+r+1,cmp);
    for(int i=mid+1,L=l;i<=r;++i){
        while(L<=mid && b[L].a<=c[i].mi)bit.add(b[L].mx,dp[b[++L].id]);
        tomax(dp[c[i].id],bit.query(c[i].a)+1);
    }
    bit.clear();
    CDQ(mid+1,r);
    sort(b+l,b+r+1);
}
int main(){
    
    for(int i=1;i<=n;++i)
        b[++cnt] = {mi[i],mx[i],a[i],i};
   	
}

bzoj2001

线段树分治,把修改变成对应值改成作用域在时间区间的问题

将子树里(不包括根)的所有边视为 \(-inf\) ,尝试将根到当前结点的所有可能的边加入并查集,能加入的边在这棵子树内必选

将必选的边选完,将子树里(不包括根)的所有边视为 \(inf\) ,尝试将根到当前结点的所有可能的边加入并查集,能加入的边在这棵子树可能选中(数量级较小,和修改总次数相同)

vector<Edge> e[N<<2],g[N<<2],now[20];
void change(int p,int l,int r,int L,int R,Edge v){
	if(l>=L && r<=R){
		g[p].push_back(v);
		return;
	}
	e[p].push_back(v);
	int mid = l+r>>1;
	if(mid>=L)change(ls,l,mid,L,R,v);
	if(mid<R)change(rs,mid+1,r,L,R,v);
}
//now 记录从根到当前结点,可能在最小生成树里的边(去掉了一定和不可能的) 
void dfs(int p,int l,int r,int d){
	for(auto v:g[p])now[d].push_back(v);
	sort(now[d].begin(),now[d].end());
	int tmp = st.top;
	if(l==r){
		for(auto v:now[d])st.uni(v.u,v.v);
		st.pop(tmp);
		printf("%d\n",sum);
		return;
	}
	for(auto v:e[p])st.uni(v.u,v.v);
	for(int i=0;i<now[d].size();++i){
		auto v = now[d][i];
		if(st.uni(v.u,v.v))mark[i] = 1;
	}
	st.pop(tmp);
	for(int i=0;i<now[d].size();++i){
		auto v = now[d][i];
		if(mark[i])st.uni(v.u,v,v),mark[i] = 0;
	}
	int tmp1 = st.top;
	now[d+1].clear();
	for(int i=0;i<now[d].size();++i){
		auto v = now[d][i];
		if(st.uni(v.u,v.v))now[d+1].push_back(v);
	}
	st.pop(tmp1);
	dfs(ls,l,mid,d+1),dfs(rs,mid+1,r,d+1);
	st.pop(tmp);
}
posted @ 2025-11-28 09:57  huhangqi  阅读(4)  评论(0)    收藏  举报
/*
*/