zoukankan      html  css  js  c++  java
  • [bzoj3809]Gty的二逼妹子序列【莫队】【分块】

    【题目描述】

    Description

    Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题。
    对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数。
    为了方便,我们规定妹子们的美丽度全都在[1,n]中。
    给定一个长度为n(1<=n<=100000)的正整数序列s(1<=si<=n),对于m(1<=m<=1000000)次询问“l,r,a,b”,每次输出sl...sr中,权值∈[a,b]的权值的种类数。

    Input

    第一行包括两个整数n,m(1<=n<=100000,1<=m<=1000000),表示数列s中的元素数和询问数。
    第二行包括n个整数s1...sn(1<=si<=n)。
    接下来m行,每行包括4个整数l,r,a,b(1<=l<=r<=n,1<=a<=b<=n),意义见题目描述。
    保证涉及的所有数在C++的int内。
    保证输入合法。

    Output

    对每个询问,单独输出一行,表示sl...sr中权值∈[a,b]的权值的种类数。

    Sample Input

    10 10
    4 4 5 1 4 1 5 1 2 1
    5 9 1 2
    3 4 7 9
    4 4 2 5
    2 3 4 7
    5 10 4 4
    3 9 1 1
    1 4 5 9
    8 9 3 3
    2 2 1 6
    8 9 1 4

    Sample Output

    2
    0
    0
    2
    1
    1
    1
    0
    1
    2

    HINT

    样例的部分解释:


    5 9 1 2

    子序列为4 1 5 1 2

    在[1,2]里的权值有1,1,2,有2种,因此答案为2。


    3 4 7 9

    子序列为5 1

    在[7,9]里的权值有5,有1种,因此答案为1。


    4 4 2 5

    子序列为1

    没有权值在[2,5]中的,因此答案为0。


    2 3 4 7

    子序列为4 5

    权值在[4,7]中的有4,5,因此答案为2。


    建议使用输入/输出优化。

    Source

    【题解】

    第一眼看到是经典的莫队+树状数组维护。

    但修改个数为O(n sqrt n),查询个数为 O(m)

    修改/查询复杂度为O(log n),这样不大平均,会TLE

    考虑分块,O(1)修改,O(sqrt n)查询。

     总复杂度为O((n+m) sqrt n) 能顺利通过此题。

    /* --------------
        user Vanisher
        problem bzoj-3809
    ----------------*/
    # include <bits/stdc++.h>
    # define 	ll 		long long
    # define 	N 		100010
    # define 	M 		1000010
    using namespace std;
    int read(){
    	int tmp=0, fh=1; char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    	return tmp*fh;
    }
    struct node{
    	int l,r,a,b,id;
    }q[M];
    int cnt[N],num[N],ans[M],T,n,m,p[N],h[N]; 
    bool cmp(node x, node y){
    	return x.l/T<y.l/T||x.l/T==y.l/T&&x.r<y.r;
    }
    void modify(int x, int tag){
    	if (cnt[x]==0) num[x/T]++;
    	cnt[x]+=tag;
    	if (cnt[x]==0) num[x/T]--;
    }
    int query(int l, int r){
    	int sum=0;
    	for (int i=p[l]+1; i<=p[r]-1; i++)
    		sum=sum+num[i];
    	if (p[l]==p[r]){
    		for (int i=l; i<=r; i++)
    			sum=sum+(cnt[i]>0);
    	}
    	else {
    		for (int i=l; p[i]==p[l]; i++)
    			sum=sum+(cnt[i]>0);
    		for (int i=r; p[i]==p[r]; i--)
    			sum=sum+(cnt[i]>0);
    	}
    	return sum;
    }
    int main(){
    	n=read(), m=read(); 
    	T=(int)(sqrt(n)+0.5);
    	for (int i=1; i<=n; i++){
    		h[i]=read();
    		p[i]=i/T;
    	}
    	for (int i=1; i<=m; i++){
    		q[i].l=read(), q[i].r=read(); q[i].a=read(), q[i].b=read(); q[i].id=i;
    	}
    	sort(q+1,q+m+1,cmp);
    	int nowl=1, nowr=0;
    	for (int i=1; i<=m; i++){
    		while (nowr<q[i].r) modify(h[++nowr],1);
    		while (nowr>q[i].r) modify(h[nowr--],-1);
    		while (nowl<q[i].l) modify(h[nowl++],-1);
    		while (nowl>q[i].l) modify(h[--nowl],1);
    		ans[q[i].id]=query(q[i].a,q[i].b);
    	}
    	for (int i=1; i<=m; i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    

  • 相关阅读:
    SQL SERVER 2008的元数据视图
    SQL Server 2008 中的 XML 功能
    SQL SERVER 2008的层次结构支持
    C#打包程序
    SQL SERVER 2008的top增强
    SQL SERVER导出数据字典
    SQL SERVER 2008的转置函数PIVOT
    SQL SERVER 2008的SQLCMD模式
    SQL SERVER 2008传递表值参数
    SQL Server 2005导出表中数据的SQL脚本形式(即INSERT语句)
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136015.html
Copyright © 2011-2022 走看看