zoukankan      html  css  js  c++  java
  • BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块

    题目描述

    输入

    输出

    样例输入

    3 4
    1 2 2
    1 2 1 3
    1 2 1 1
    1 3 1 3
    2 3 2 3

    样例输出

    2 2
    1 1
    3 2
    2 1

    提示

    N=100000,M=1000000

    莫队+树状数组:

    先考虑每次询问没有权值区间限制的情况,将询问离线排序,用一个数组记录答案,莫队即可。

    但现在每次询问有了查询的权值区间,显然一个数组无法记录答案,我们用树状数组来记录答案。

    对于第一问直接用树状数组即可,对于第二问先用数组记录每个权值是否出现过再用树状数组维护即可。

    莫队时间复杂度是$O(mlog_{n}sqrt{n})$,查询时间复杂度是$O(mlog_{n})$。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    struct lty
    {
        int l,r;
        int a,b;
        int num;
    }q[1000010];
    int ans1[1000010];
    int ans2[1000010];
    int v1[100010];
    int v2[100010];
    int t[100010];
    int s[100010];
    int n,m;
    int L,R;
    int block;
    inline bool cmp(lty x,lty y)
    {
        return (x.l/block)==(y.l/block)?x.r<y.r:x.l<y.l;
    }
    inline void add1(int x,int val)
    {
        for(int i=x;i<=100000;i+=i&-i)
        {
            v1[i]+=val;
        }
    }
    inline void add2(int x,int val)
    {
        for(int i=x;i<=100000;i+=i&-i)
        {
            v2[i]+=val;
        }
    }
    inline int ask1(int x)
    {
        int res=0;
        for(int i=x;i;i-=i&-i)
        {
            res+=v1[i];
        }
        return res;
    }
    inline int ask2(int x)
    {
        int res=0;
        for(int i=x;i;i-=i&-i)
        {
            res+=v2[i];
        }
        return res;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        block=(int)sqrt(n+0.5);
        block-=rand()%30;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&s[i]);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b);
            q[i].num=i;
        }
        sort(q+1,q+1+m,cmp);
        L=1;
        for(int i=1;i<=m;i++)
        {
            while(L>q[i].l)
            {
                L--;
                if(!t[s[L]])
                {
                    add2(s[L],1);
                }
                t[s[L]]++;
                add1(s[L],1);
            }
            while(R<q[i].r)
            {
                R++;
                if(!t[s[R]])
                {
                    add2(s[R],1);
                }
                t[s[R]]++;
                add1(s[R],1);
            }
            while(L<q[i].l)
            {
                if(t[s[L]]==1)
                {
                    add2(s[L],-1);
                }
                t[s[L]]--;
                add1(s[L],-1);
                L++;
            }
            while(R>q[i].r)
            {
                if(t[s[R]]==1)
                {
                    add2(s[R],-1);
                }
                t[s[R]]--;
                add1(s[R],-1);
                R--;
            }
            ans1[q[i].num]=ask1(q[i].b)-ask1(q[i].a-1);
            ans2[q[i].num]=ask2(q[i].b)-ask2(q[i].a-1);
        }
        for(int i=1;i<=m;i++)
        {
            printf("%d %d
    ",ans1[i],ans2[i]);
        }
    }
    

    莫队+分块:

    可以发现莫队+树状数组的做法时间复杂度主要在双指针移动时对答案的维护。

    我们将树状数组改成分块,那么单次移动指针时间复杂度为$O(1)$,而单次查询的时间复杂度是$O(sqrt{n})$。

    这样莫队的时间复杂度是$O(msqrt{n})$,查询的时间复杂度为$O(msqrt{n})$。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    struct lty
    {
    	int l,r;
    	int a,b;
    	int num;
    }q[1000010];
    int ans1[1000010];
    int ans2[1000010];
    int sum1[100010];
    int sum2[100010];
    int v1[100010];
    int v2[100010];
    int t[100010];
    int s[100010];
    int n,m;
    int L,R;
    int block;
    inline bool cmp(lty x,lty y)
    {
    	return (x.l/block)==(y.l/block)?x.r<y.r:x.l<y.l;
    }
    inline int get(int x)
    {
    	return (x-1)/200+1;
    }
    inline void add1(int x,int val)
    {
    	sum1[get(x)]+=val;
    	v1[x]+=val;
    }
    inline void add2(int x,int val)
    {
    	sum2[get(x)]+=val;
    	v2[x]+=val;
    }
    inline int ask1(int l,int r)
    {
    	int res=0;
    	for(int i=get(l)+1;i<=get(r)-1;i++)
    	{
    		res+=sum1[i];
    	}
    	if(get(l)==get(r))
    	{
    		for(int i=l;i<=r;i++)
    		{
    			res+=v1[i];
    		}
    		return res;
    	}
    	for(int i=l;i<=min(n,get(l)*200);i++)
    	{
    		res+=v1[i];
    	}
    	for(int i=(get(r)-1)*200+1;i<=r;i++)
    	{
    		res+=v1[i];
    	}
    	return res;
    }
    inline int ask2(int l,int r)
    {
    	int res=0;
    	for(int i=get(l)+1;i<=get(r)-1;i++)
    	{
    		res+=sum2[i];
    	}
    	if(get(l)==get(r))
    	{
    		for(int i=l;i<=r;i++)
    		{
    			res+=v2[i];
    		}
    		return res;
    	}
    	for(int i=l;i<=min(n,get(l)*200);i++)
    	{
    		res+=v2[i];
    	}
    	for(int i=(get(r)-1)*200+1;i<=r;i++)
    	{
    		res+=v2[i];
    	}
    	return res;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	block=(int)sqrt(n+0.5);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&s[i]);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].a,&q[i].b);
    		q[i].num=i;
    	}
    	sort(q+1,q+1+m,cmp);
    	L=1;
    	for(int i=1;i<=m;i++)
    	{
    		while(L>q[i].l)
    		{
    			L--;
    			if(!t[s[L]])
    			{
    				add2(s[L],1);
    			}
    			t[s[L]]++;
    			add1(s[L],1);
    		}
    		while(R<q[i].r)
    		{
    			R++;
    			if(!t[s[R]])
    			{
    				add2(s[R],1);
    			}
    			t[s[R]]++;
    			add1(s[R],1);
    		}
    		while(L<q[i].l)
    		{
    			if(t[s[L]]==1)
    			{
    				add2(s[L],-1);
    			}
    			t[s[L]]--;
    			add1(s[L],-1);
    			L++;
    		}
    		while(R>q[i].r)
    		{
    			if(t[s[R]]==1)
    			{
    				add2(s[R],-1);
    			}
    			t[s[R]]--;
    			add1(s[R],-1);
    			R--;
    		}
    		ans1[q[i].num]=ask1(q[i].a,q[i].b);
    		ans2[q[i].num]=ask2(q[i].a,q[i].b);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		printf("%d %d
    ",ans1[i],ans2[i]);
    	}
    }
  • 相关阅读:
    json和xml数据的解析
    block(闭包)
    自定义控件注意点
    字符串使用
    如何用运行时,给系统分类添加属性?
    论代码规范
    常用设计模式
    多控制器管理
    GDI+学习及代码总结之-----画笔 .
    MFC程序添加Web浏览器控件(IE控件)
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10602963.html
Copyright © 2011-2022 走看看