zoukankan      html  css  js  c++  java
  • CDQ分治

    首先,偏序是什么

    一维偏序就是数列中对于每个(x)有多少个(aleq x)

    二维偏序就是二元组((x,y))有多少((a,b))满足(aleq x wedge bleq y)

    ...

    一维偏序可以直接排序

    二维偏序联想到逆序对可以给第一位排序第二维数据结构

    三维偏序第一维排序第二维cdq分治第三维树状数组

    其实二维还有一个方法就是归并排序

    每次二分时顺便统计左边对右边的影响

    cdq分治就是这样

    没了。。??

    update kdtree txdy!

    陌上花开

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define M 300001
    using namespace std;
    
    int n,m,k,a[M],c[M],cnt[M];
    struct vv {	int a,b,c,id,num,ans;} d[M],tmp[M];
    bool cmp(vv a,vv b) 
    {
    	if(a.a!=b.a) return a.a<b.a;
    	if(a.b!=b.b) return a.b<b.b;
    	return a.c<b.c;
    }
    
    void add(int x,int k) { for(int i=x;i<=m;i+=i & -i) c[i]+=k;}
    int ask(int x) { int ans=0; for(int i=x;i>0;i-=i & -i) ans+=c[i]; return ans;}
    
    void cdq(int l,int r)
    {
    	if(l==r) return ;
    	int mid=(l+r)>>1,cnt=0, j=l;
    	cdq(l,mid); cdq(mid+1,r);
    	for(int i=mid+1;i<=r;i++)
    	{
    		while(d[j].b<=d[i].b && j<=mid) add(d[j].c,d[j].num), tmp[cnt++]=d[j++];
    		d[i].ans+=ask(d[i].c); tmp[cnt++]=d[i];  
    	}
    	for(int i=l;i<j;i++) add(d[i].c,-d[i].num);
    	for(int i=mid;i>=j;i--) d[r+i-mid]=d[i]; 
    	for(int i=0;i<cnt;i++) d[l+i]=tmp[i];
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) scanf("%d%d%d",&tmp[i].a,&tmp[i].b,&tmp[i].c), tmp[i].num=1;
    	sort(tmp+1,tmp+1+n,cmp); 
    	for(int i=1;i<=n;i++)
    		if(tmp[i].a!=tmp[i-1].a || tmp[i].b!=tmp[i-1].b || tmp[i].c!=tmp[i-1].c) d[++k]=tmp[i], d[k].id=k;
    		else d[k].num+=1;
    	cdq(1,k); 
    	for(int i=1;i<=k;i++) cnt[d[i].ans+d[i].num-1]+=d[i].num;
    	for(int i=0;i<n;i++) printf("%d
    ",cnt[i]);
    }
    

    这辈子都学不会斜率优化了

    [USACO07JAN]Cow School G

    考虑前k大的数的答案是(frac{sum_{i=1}^k a_i}{sum_{i=1}^k b_i}=frac A B)

    移向就是(sum_{i=1}^k Ba_i-Ab_i=0), 可以观察到如果有另一个集合的和大于0的话那么前k大就不是最优答案

    换句话说就是找到不在前k大里的最大的(Ba_x-Ab_x)和前k大里最小的(Ba_y-Ab_y)如果有前一个大于后一个,那么上面的式子就会大于零,也就是找到了一个比选前k个要优的答案

    再观察这个式子(Ba_x-Ab_x=C)(frac B A a_x-frac C A=b_x)要求最大/最小化(frac C A)这里就是斜率优化

    然而斜率优化和cdq分治都是我这辈子学不会的东西

    ctz_tttttttttttttttttttttttttttttql!!!!!!!!!!!!!!!!!!!!!!

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    
    using namespace std;
    
    const int M = 200001;
    int n,m,k,tp,tl,A[M],B[M];
    double ansx[M],ansn[M];
    struct vv 
    {
    	int id,x,y,tag;
    } d[M],tmp[M];
    
    struct pt
    {
    	int x,y;
    } st[M],a[M];
    
    pt operator - (const pt&a,const pt&b) {return {a.x-b.x,a.y-b.y}; }
    
    double operator ^ (const pt&a,const pt&b){return 1.0*a.x*b.y-1.0*a.y*b.x;}
    
    void ins(int x,int y,int k)
    {
    	while(tp>tl &&((st[tp-1]-st[tp])^((pt){x,y}-st[tp]))*k<0) tp--;
    	st[++tp]={x,y};
    }
    
    double ask(double k,pt a)
    {
    	return k*a.x-a.y;
    }
    
    void pp(double k,int tg)
    {
    	while(tp>tl && (ask(k,st[tl])*tg<ask(k,st[tl+1])*tg)) tl++;
    }
    
    bool cmp(vv a,vv b,int k)
    {
    	if(a.tag!=b.tag) return a.tag<b.tag;
    	if(a.tag==0)
    	{
    		if(a.x<b.x || (a.x==b.x && k*a.y>k*b.y)) return 1;
    		return 0;
    	}
    	return 1.0*a.x/a.y*k>1.0*b.x/b.y*k;
    }
    
    void cdq1(int l,int r)
    {
    	if(l==r) return; 
    	int mid=(l+r)>>1;
    	cdq1(l,mid); cdq1(mid+1,r);
    	tp=0, tl=1;
    	for(int i=l;i<=mid;i++) if(!d[i].tag) ins(d[i].x,d[i].y,-1);
    	for(int i=mid+1;i<=r;i++) if(d[i].tag)
    	{
    
    		pp(1.0*d[i].x/d[i].y,1);
    		if(tp>=tl) ansx[d[i].id]=max(ansx[d[i].id],ask(1.0*d[i].x/d[i].y,st[tl]));
    	} 
    	
    	int Tl=l,Tr=mid+1, t=0;
    	while(Tl<=mid && Tr<=r)
    	{
    		if(cmp(d[Tl],d[Tr],-1))  tmp[++t]=d[Tl++];
    		else tmp[++t]=d[Tr++];
    	}
    	while(Tl<=mid) tmp[++t]=d[Tl++];
    	while(Tr<=r) tmp[++t]=d[Tr++];
    	for(int i=1;i<=t;i++) d[l+i-1]=tmp[i];
    }
    
    void cdq2(int l,int r)
    {
    	if(l==r) return; 
    	int mid=(l+r)>>1;
    	cdq2(l,mid); cdq2(mid+1,r);
    	tp=0, tl=1;
    	for(int i=l;i<=mid;i++) if(!d[i].tag) ins(d[i].x,d[i].y,1);
    	for(int i=mid+1;i<=r;i++) if(d[i].tag)
    	{
    		pp(1.0*d[i].x/d[i].y,-1);
    		if(tp>=tl) ansn[d[i].id]=min(ansn[d[i].id],ask(1.0*d[i].x/d[i].y,st[tl]));
    	} 
    	
    	int Tl=l,Tr=mid+1, t=0;
    	while(Tl<=mid && Tr<=r)
    	{
    		if(cmp(d[Tl],d[Tr],1))  tmp[++t]=d[Tl++];
    		else tmp[++t]=d[Tr++];
    	}
    	while(Tl<=mid) tmp[++t]=d[Tl++];
    	while(Tr<=r) tmp[++t]=d[Tr++];
    	for(int i=1;i<=t;i++) d[l+i-1]=tmp[i];
    }
    
    bool Cmp(pt a,pt b) {return 1.0*a.x/a.y>1.0*b.x/b.y;}
    bool Cmp_(pt a,pt b) {return 1.0*a.x/a.y<1.0*b.x/b.y;}
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d%d",&a[i].x,&a[i].y);
    	}
    	sort(a+1,a+1+n,Cmp); int t=0;
    	for(int i=1;i<=n;i++)
    	{
    		t++;
    		d[t].id=i, d[t].x=a[i].x, d[t].y=a[i].y, d[t].tag=0;
    		t++;
    		A[i]=A[i-1]+a[i].x, B[i]=B[i-1]+a[i].y;
    		d[t].id=i; d[t].y=A[i], d[t].x=B[i], d[t].tag=1;
    		ansn[i]=1e10;
    	}
    	cdq2(1,t); sort(a+1,a+1+n,Cmp_);
    	t=0;
    	for(int i=1;i<=n;i++)
    	{
    		if(i>1)t++;
    		if(i>1)d[t].id=i-1, d[t].y=A[n-i+1], d[t].x=B[n-i+1], d[t].tag=1;
    		t++;
    		d[t].id=i, d[t].x=a[i].x, d[t].y=a[i].y, d[t].tag=0;
    		ansx[i]=-0x3f3f3f3f;
    	}
    
    	cdq1(1,t);
    	int sm=0; 
    	for(int i=n-1;i>=1;i--)	if(ansn[i]<ansx[n-i]) A[++sm]=n-i;
    	printf("%d
    ",sm);
    	for(int i=1;i<=sm;i++) printf("%d
    ",A[i]);
    }
    
  • 相关阅读:
    FileUpload1上传控件
    docker如何push镜像到docker hub个人的仓库
    docker的ubuntu镜像无ifconfig和ping命令
    keystone同步数据库的时候提示error
    openstack安装dashboard后访问horizon出错 500 or 504
    装了ubuntu之后,只能进入ubuntu系统,不能进入windows系统
    Kernal Panic
    无法获得锁 /var/lib/dpkg/lock -open
    用户 'NT AUTHORITYIUSR' 登录失败
    配置错误:不能在此路径中使用此配置节。
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/10383590.html
Copyright © 2011-2022 走看看