重修 CDQ 分治

简介

把动态问题转化为静态问题。

静态问题:没有修改操作的问题,或者所有查询操作都在修改操作之后的问题

动态问题:修改和查询操作交叉的问题

\[\large{动态问题\xrightarrow{CDQ}静态问题+\log\uparrow} \]

例题

P3810 【模板】三维偏序(陌上花开)

就是个模板。

P4390 [BOI2007]Mokia 摩基亚

我们按照时间分治 \(solve(l,r)\)

  1. \(solve(l,mid)\),因为时间无后效性。

  2. 再计算 \([l,mid]\) 的加点操作给 \([mid+1,r]\) 的贡献。

  3. 最后,由于 \([l,mid]\)\([mid+1,r]\) 的贡献已经算完,直接放心 \(solve(mid+1,r)\)

所以这层分治之内唯一要解决的就是第二步。

求矩形和可以二维差分转化为四个 2-sides 矩形。

所以这道题可转化为静态问题:

给定平面上的一些点(带点权)和一些询问,每次询问需回答在一个坐标左下角的点权和。

这可以类似扫描线解决。

点击查看代码
//We'll be counting stars.
//#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false)
#define fir first
#define sec second
#define mkp make_pair
#define pb emplace_back
#define mem(x,y) memset(x,y,sizeof(x))
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Rof(i,j,k) for(int i=j;i>=k;i--)
#define Fe(x,y) for(int x=head[y];x;x=e[x].nxt)
#define ckmx(a,b) a=max(a,b)
#define ckmn(a,b) a=min(a,b)
#define fin(s) freopen(s,"r",stdin)
#define fout(s) freopen(s,"w",stdout)
#define file(s) fin(s".in");fout(s".out")
#define debug cerr<<"Passed line #"<<__LINE__<<endl
#define numlim(s) cerr<<numeric_limits<s>::min()<<"~"<<numeric_limits<s>::max()<<endl
#define ll long long
const ll mod=1000000007;
inline ll pw(ll x,ll y){ll r=1;while(y){if(y&1)r=r*x%mod;x=x*x%mod;y>>=1;}return r;}
inline void mad(ll &a,ll b){a=(a+b)%mod;while(a<0)a+=mod;}
inline void mmu(ll &a,ll b){a=(a*b)%mod;while(a<0)a+=mod;}
#define inv(a) pw(a,mod-2)
#define int long long
#define N 170010
#define V 2000001
#define low (x&(-x))
int n=0,lim,ans[N],c[V],buf[V],tot=0;
bool vis[V];
inline void add(int x,int y){
	while(x<=lim){
		c[x]+=y;
		if(!vis[x]){
			vis[x]=1;
			buf[++tot]=x;
		}
		x+=low;
	}
}
inline int que(int x){
	int res=0;
	while(x){
		res+=c[x];
		x-=low;
	}
	return res;
}
inline void clear(){
	int x;
	while(tot){
		x=buf[tot--];
		vis[x]=0;
		c[x]=0;
	}
}
struct Que{
	bool opt;//0 add 1 que
	int x,y,k,co;
	friend bool operator<(Que x,Que y){
		if(x.x!=y.x) return x.x<y.x;
		if(x.y!=y.y) return x.y<y.y;
		return x.opt<y.opt;
	}
}b[4*N];//询问是要 *4 的 
int bt;
struct Node{
	bool opt;
	int x,y,xx,yy,k;
}a[N];
#define mid ((l+r)>>1)
void work(int l,int r){
	if(l==r) return ;
	work(l,mid);
	bt=0;
	For(i,l,mid) if(!a[i].opt) b[++bt]=(Que){0,a[i].x,a[i].y,a[i].k,0};
	For(i,mid+1,r) if(a[i].opt){
		b[++bt]=(Que){1,a[i].xx ,a[i].yy ,i, 1};
		b[++bt]=(Que){1,a[i].xx ,a[i].y-1,i,-1};
		b[++bt]=(Que){1,a[i].x-1,a[i].yy ,i,-1};
		b[++bt]=(Que){1,a[i].x-1,a[i].y-1,i, 1};
	}
	sort(b+1,b+1+bt);
	For(i,1,bt)
		if(!b[i].opt) add(b[i].y,b[i].k);
		else ans[b[i].k]+=b[i].co*que(b[i].y);
	clear();
	work(mid+1,r);
}
int32_t main(){IOS;
	int x;
	cin>>x>>lim;
	while(1){
		cin>>x;
		if(x==3) break;
		n++;
		a[n].opt=x-1;
		if(!a[n].opt) cin>>a[n].x>>a[n].y>>a[n].k;
		else cin>>a[n].x>>a[n].y>>a[n].xx>>a[n].yy;
	}
	work(1,n);
	For(i,1,n) if(a[i].opt) cout<<ans[i]<<endl;
return 0;}

P2487 [SDOI2011]拦截导弹

也类似模板,但是要算概率,直接古典概型上即可。

点击查看代码
//We'll be counting stars.
//#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false)
#define fir first
#define sec second
#define mkp make_pair
#define pb emplace_back
#define mem(x,y) memset(x,y,sizeof(x))
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Rof(i,j,k) for(int i=j;i>=k;i--)
#define Fe(x,y) for(int x=head[y];x;x=e[x].nxt)
#define ckmx(a,b) a=max(a,b)
#define ckmn(a,b) a=min(a,b)
#define fin(s) freopen(s,"r",stdin)
#define fout(s) freopen(s,"w",stdout)
#define file(s) fin(s".in");fout(s".out")
#define debug cerr<<"Passed line #"<<__LINE__<<endl
#define numlim(s) cerr<<numeric_limits<s>::min()<<"~"<<numeric_limits<s>::max()<<endl
#define int long long
#define db double
#define N 50010
#define pi pair<int,db>
struct Node{
	int x,y,id;
	friend bool operator<(Node x,Node y){return x.id<y.id;}
}a[N];
inline bool cmp(Node x,Node y){return x.x==y.x?x.id<y.id:x.x>y.x;}
int n,s[N],lim,st[N],tot=0;
struct node{
	int mxlen;
	db cnt;
	void init(){mxlen=cnt=1;}
	void clear(){mxlen=-1;cnt=0;}
	friend node operator+(node x,node y){
		if(x.mxlen==y.mxlen) return (node){x.mxlen,x.cnt+y.cnt};
		else return x.mxlen>y.mxlen?x:y;
	}
	friend void operator+=(node &x,node y){x=x+y;}
}t[N<<2],f[2][N];
void lisan(){//lisan for a.y
	For(i,1,n) s[i]=a[i].y;
	sort(s+1,s+1+n);
	lim=unique(s+1,s+1+n)-s-1;
	For(i,1,n) a[i].y=lower_bound(s+1,s+1+lim,a[i].y)-s;
}
#define mid ((l+r)>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
void build(int rt,int l,int r){
	t[rt].clear();
	if(l==r) return ;
	build(ls,l,mid);
	build(rs,mid+1,r);
}
void add(int rt,int l,int r,int x,node val){
	if(l==r){
//		cout<<t[rt].mxlen<<" "<<t[rt].cnt<<endl;
		t[rt]+=val;
		st[++tot]=rt;
//		cout<<x<<"!"<<val.mxlen<<" "<<val.cnt<<" "<<t[rt].mxlen<<" "<<t[rt].cnt<<endl;
		return ;
	}
	if(x<=mid) add(ls,l,mid,x,val);
	else add(rs,mid+1,r,x,val);
	t[rt]=t[ls]+t[rs];
}
node que(int rt,int l,int r,int x,int y){
	if(l==x && r==y) return t[rt];
	if(y<=mid) return que(ls,l,mid,x,y);
	else if(x>mid) return que(rs,mid+1,r,x,y);
	return que(ls,l,mid,x,mid)+que(rs,mid+1,r,mid+1,y);
}
void clear(){
	int x;
	while(tot){
		x=st[tot--];
		while(x && t[x].mxlen!=-1){
			t[x].clear();
			x>>=1;
		}
	}
}
node addlen(node x){x.mxlen++;return x;}
void solve(int l,int r){
	if(l==r) return ;
//	cout<<"solve "<<l<<"~"<<r<<endl;
	solve(l,mid);
	sort(a+l,a+r+1,cmp);
//	cout<<"mid   "<<l<<"~"<<r<<" "; For(i,l,r) cout<<a[i].id<<" "; cout<<endl;
	For(i,l,r)
		if(a[i].id<=mid) add(1,1,lim,a[i].y,f[0][a[i].id]);
		else f[0][a[i].id]+=addlen(que(1,1,lim,a[i].y,lim));
	clear();
	sort(a+l,a+r+1);
	solve(mid+1,r);
//	cout<<"end   "<<l<<"~"<<r<<" "; For(i,l,r) cout<<f[0][i].mxlen<<" "; cout<<endl;
}
int32_t main(){IOS;
	cin>>n;
	For(i,1,n) cin>>a[i].x>>a[i].y;
	lisan();
	build(1,1,lim);
	cout<<fixed<<setprecision(5);
	For(i,1,n) f[0][i].init();
	reverse(a+1,a+1+n);
	For(i,1,n) a[i].x*=-1;
	For(i,1,n) a[i].y=lim-a[i].y+1;
	For(i,1,n) a[i].id=i;
	solve(1,n);
	For(i,1,n) f[1][i]=f[0][n-i+1];
	For(i,1,n) f[0][i].init();
	reverse(a+1,a+1+n);
	For(i,1,n) a[i].x*=-1;
	For(i,1,n) a[i].y=lim-a[i].y+1;
	For(i,1,n) a[i].id=i;
//	For(i,1,n) cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].id<<endl; 
	solve(1,n);
//	For(i,1,n) cout<<f[0][i].mxlen<<">"<<f[0][i].cnt<<endl; 
//	For(i,1,n) cout<<f[1][i].mxlen<<"<"<<f[1][i].cnt<<endl; 
	int ans=0;
	db sum=0;
	For(i,1,n) ckmx(ans,f[0][i].mxlen); cout<<ans<<endl;
	For(i,1,n) if(f[0][i].mxlen==ans) sum+=f[0][i].cnt;
	For(i,1,n)
		if(f[0][i].mxlen+f[1][i].mxlen-1<ans) cout<<(db)0<<" ";
		else cout<<f[0][i].cnt*f[1][i].cnt/sum<<" ";
	cout<<endl;
return 0;}

P4169 [Violet]天使玩偶/SJY摆棋子

不是那个 sjy

发现哈密尔顿距离不好搞,我们将绝对值拆开,每次询问拆成左下左上右下右上四个子问题的最小值。

那和 P4390 [BOI2007]Mokia 摩基亚 不就类似了?

点击查看代码
//We'll be counting stars.
#include<bits/stdc++.h>
using namespace std;
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Rof(i,j,k) for(int i=j;i>=k;i--)
#define ckmx(a,b) a=max(a,b)
#define ckmn(a,b) a=min(a,b)
#define N 600010
#define V 1000002
#define low (x&(-x))
const int inf=1e7;
int c[V],buf[N],bt=0;
void add(int x,int y){
	buf[++bt]=x;
	while(x<V){
		ckmx(c[x],y);
		x+=low;
	}
}
int que(int x){
	int res=0;
	while(x){
		ckmx(res,c[x]);
		x-=low;
	}
	return res;
}
void clear(){
	int x;
	while(bt){
		x=buf[bt--];
		while(x<V){
			c[x]=0;
			x+=low; 
		}
	}
}
struct node{
	bool opt;
	int x,y;
}a[N];
struct Node{
	bool opt;
	int x,y,id;
	friend bool operator<(Node x,Node y){return x.x!=y.x?x.x<y.x:(x.y!=y.y?x.y<y.y:x.opt<y.opt);}
}b[N];
int n,m,f[N],tot;
void solve(int l,int r){
	if(l==r) return ;
	int x,mid=(l+r)>>1;
	solve(l,mid);
	tot=0;
	For(i,l,mid) if(!a[i].opt) b[++tot]=(Node){a[i].opt,a[i].x,a[i].y,i};
	For(i,mid+1,r) if(a[i].opt) b[++tot]=(Node){a[i].opt,a[i].x,a[i].y,i};
	sort(b+1,b+1+tot);
	For(i,1,tot)
		if(!b[i].opt) add(b[i].y,b[i].x+b[i].y);
		else x=que(b[i].y),ckmn(f[b[i].id],x?b[i].x+b[i].y-x:inf);
	clear();
	solve(mid+1,r);
}
int32_t main(){
	scanf("%d%d",&n,&m);
	For(i,1,n) scanf("%d%d",&a[i].x,&a[i].y);
	For(i,1,n) a[i].opt=0;
	int x;
	For(i,n+1,n+m){
		scanf("%d%d%d",&x,&a[i].x,&a[i].y);
		a[i].opt=x-1;
	}
	n+=m; 
	For(i,1,n) a[i].x++;
	For(i,1,n) a[i].y++;
	For(i,1,n) f[i]=inf;
	solve(1,n);
	For(i,1,n) a[i].x=V+1-a[i].x;
	solve(1,n);
	For(i,1,n) a[i].y=V+1-a[i].y;
	solve(1,n);
	For(i,1,n) a[i].x=V+1-a[i].x;
	solve(1,n);
	For(i,1,n) if(a[i].opt) printf("%d\n",f[i]);
return 0;}
posted @ 2022-06-07 19:13  ShaoJia  阅读(43)  评论(0)    收藏  举报