• 几道很Interesting的偏序问题


    若干道偏序问题(STL,分块)

    找了4道题目
    BZOJ陌上花开(权限题,提供洛谷链接)
    Cogs2479偏序
    Cogs2580偏序II
    Cogs2639偏序++


    作为一个正常人,肯定先看三维偏序
    做法很多呀
    首先,由于

    智商不够数据结构来补 $ $--菊开

    所以我们用最傻逼的数据结构来做这道题目
    第一维:排序
    第二维:树状数组
    第三维:平衡树
    于是乎,我们得到了一个复杂度为(O(nlog^2n))的做法
    并且常数巨大
    这个做法到这里去看


    第二种做法 CDQ分治 相信大家都会逆序对的求法 可以归并排序求逆序对 逆序对相当于是一个二维偏序 第一维就相当于它的位置 第二维就是值 每次归并排序的时候相当于分成了两部分 只有左侧的部分才能对右侧的部分产生贡献

    这里同理,第一维排序
    第二维类似于归并排序就行合并
    同时一遍归并一边计算第三维

    是不是想到了逆序对还可以用树状数组来求
    所以这里一样的,
    第三维用一个BIT来求就行了

    这种做法看这里

    恩,三维偏序没了


    现在看Cogs的【偏序】

    四维偏序模板题
    可以顺着三维偏序来思考
    既然多了一维
    我就多套个CDQ分治呀
    那不就是CDQ分治套树套树
    或者CDQ分治套CDQ分治加树状数组
    复杂度(O(nlog^3n))
    好像也可以诶。。。


    好好好
    我们继续
    Cogs【偏序II】
    不就是个五维偏序吗
    CDQ套CDQ套CDQ
    或者CDQ套CDQ套树套树
    没毛病,时间复杂度(O(nlog^4n))
    可以做可以做,没问题的


    那,我们继续
    Cogs【偏序++】
    七维偏序呀
    CDQ套CDQ套CDQ套CDQ套CDQ
    或者CDQ套CDQ套CDQ套CDQ套树套树
    时间复杂度(O(nlog^6n))
    绝对跑不过的
    而且给定的维数是K
    你还得分类讨论,看着就是不可做的题目呀。。。
    怎么办怎么办。。。


    首先,请允许我orz大佬 ——中国翅王
    orz

    这是他的PPT


    FHR的做法的复杂度:(O(nsqrt n))
    首先,我们知道
    一个向量的偏序数量
    等于它每一维的偏序数量的交集的大小
    所以,按照每一维排序之后
    我们就可以求出比每一维小的集合
    然后求一个交集就行了

    但是,暴力求,,,不现实吧。
    而且交集也不好求呀
    所以,来搞个(bitset)
    STL大法好
    但是,这样不就是(O(n^2))的暴力吗???
    没错,我们再来一发——分块大法好
    分块之后就可以把一个(n)变成(sqrt n)
    于是复杂度就降到了(O(n sqrt n))
    美滋滋
    献上丑陋的代码(【偏序++】)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<bitset>
    #include<queue>
    using namespace std;
    #define MAX 45000
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    int n,blk;
    bitset<45000> bs[15][250];
    pair<int,int> val[15][MAX];
    int bl[MAX],bll[MAX],blr[MAX];
    int K,num;
    long long Ans;
    int f[15][MAX];
    int find(int k,int x)
    {
    	int l=1,r=n,ans=0;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(val[k][mid].first<=x)ans=x,l=mid+1;
    		else r=mid-1;
    	}
    	return ans;
    }
    inline bitset<MAX> getbst(int p,int x)
    {
    	bitset<MAX> ans;ans.reset();
    	int pp=find(p,x);
    	if(pp<=0)return ans;
    	int pre=(pp-1)/blk;
    	int st=pre*blk+1;
    	ans=bs[p][pre];
    	for(int i=st;i<=pp;++i)ans.set(val[p][i].second);
    	return ans;
    }
    void Solve()
    {
    	bitset<MAX> ans;ans.reset();
    	for(int i=1;i<=n;++i)
    	{
    		ans.set();
    		for(int j=1;j<=K;++j)
    			ans&=getbst(j,f[j][i]);
    		Ans+=ans.count()-1;
    	}
    }
    int main()
    {
    	freopen("partial_order_plus.in","r",stdin);
    	freopen("partial_order_plus.out","w",stdout);
    	n=read();blk=sqrt(n);K=read()+1;
    	for(int i=1;i<=n;++i)val[1][i]=make_pair(f[1][i]=i,i);
    	for(int j=2;j<=K;++j)
    		for(int i=1;i<=n;++i)
    			val[j][i]=make_pair(f[j][i]=read(),i);
    	for(int i=1;i<=K;++i)sort(&val[i][1],&val[i][n+1]);
    	for(int i=1;i<=n;++i)
    		bl[i]=(i-1)/blk+1;num=bl[n];
    	for(int i=1;i<=num;++i)
    		bll[i]=(i-1)*blk+1,blr[i]=i*blk;blr[num]=n;
    	for(int j=1;j<=K;++j)
    		for(int i=1;i<=num;++i)
    		{
    			bs[j][i]=bs[j][i-1];
    			for(int k=bll[i];k<=blr[i];++k)
    				bs[j][i][val[j][k].second]=1;
    		}
    	Solve();
    	printf("%lld
    ",Ans);
    	return 0;
    }
    
    
  • 相关阅读:
    前端到后台ThinkPHP开发整站(4)
    前端到后台ThinkPHP开发整站(2)
    字典树模版
    KMP模版
    EXKMP模版
    Manacher模版
    AC自动机练习题1:地图匹配
    AC自动机模版
    spring.net之aop加单例模式编写无try catch程序
    父类与子类之间赋值转换
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8196312.html
Copyright © 2020-2023  润新知