zoukankan      html  css  js  c++  java
  • 题解 P4396 [AHOI2013]作业

    https://www.luogu.com.cn/problem/P4396

    一道用值域分块维护莫队的模板题。

    还是用值域分块把,用树状数组会T。

    不过还是贴一下树状数组的代码。

    #include<cmath>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    #define rint register int
    using namespace std;
    namespace FastIO
    {
    const int _SIZE = (1 << 21) + 1;
    char ibuf[_SIZE],obuf[_SIZE];
    char *iS,*iT;
    char c;
    char qu[55];
    char *oS=obuf,*oT=oS+_SIZE-1;
    bool _sign=false;
    int qr;
    // getchar
    #define gc() (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, _SIZE, stdin), (iS == iT ? EOF : *iS++)) : *iS++)
    // print the remaining part
    inline void flush() 
    {
        fwrite(obuf,1,oS-obuf,stdout);
        oS=obuf;
        return;
    }
    // putchar
    inline void putc(const char &x) 
    {
        *oS++=x;
        if(oS==oT)
            flush();
        return;
    }
    inline char getc()
    {
    	return gc();
    }
    // input a signed integer
    template <class T>
    inline void read(T &x) 
    {
    	x=0;
    	_sign=false;
        for (c=gc();c<'0'||c>'9';c=gc())
            if (c=='-')
                _sign=true;
        for (;c>='0'&&c<='9';c=gc()) 
    		x=(x<<1)+(x<<3)+(c&15);
        x=(_sign) ? (~x+1) : x;
        return;
    }
    // print a signed integer
    template <class T>
    inline void print(T x) {
        if (!x) {
        	putc('0');
        	return;
    	}
        if (x<0)
            putc('-'),x=~x+1;
        while(x) qu[++qr]=x%10+'0',x/=10;
        while(qr) putc(qu[qr--]);
        return;
    }
    // no need to call flush at the end manually!
    struct Flusher_ 
    {
        ~Flusher_() { flush(); }
    }io_flusher_;
    }  // namespace io
    using FastIO::read;
    using FastIO::print;
    using FastIO::putc;
    using FastIO::getc;
    //=================================================
    const int N=1e5+5;
    int n,m;
    struct Bits
    {
    	int c[N];
    	int res;
    	inline int lowbit(const int &x) { return x&(-x); }
    	inline void update(int x,int y) 
    	{
    		for(;x<=n;x+=lowbit(x)) 
    			c[x]+=y;
    		return;
    	}
    	inline int sum(int x)
    	{
    		res=0;
    		for(;x>=1;x-=lowbit(x)) 
    			res+=c[x];
    		return res;
    	}
    }C1,C2;
    int a[N];
    int t[N];
    struct quiz
    {
    	int l,r;
    	int a,b;
    	int ans1,ans2;
    	int o;
    }q[N];
    int siz;
    inline bool cmp(const quiz &a,const quiz &b)
    {
    	if(a.l/siz!=b.l/siz) 
    		return a.l<b.l;
    	else return a.r<b.r;
    }
    inline bool rule(const quiz &a,const quiz &b)
    {
    	return a.o<b.o;
    }
    inline void Add(int pos)
    {
    	if(t[a[pos]]==0)
    		C2.update(a[pos],1);
    	C1.update(a[pos],1);
    	++t[a[pos]];
    	return;
    }
    inline void Sub(int pos)
    {
    	if(t[a[pos]]==1) 
    		C2.update(a[pos],-1);
    	C1.update(a[pos],-1);
    	--t[a[pos]];
    	return;
    }
    int main()
    {
    //	freopen("1.in","r",stdin);
    	rint i;
    	read(n); read(m);
    	for(i=1;i<=n;i++) 
    		read(a[i]);
    	for(i=1;i<=m;i++) {
    		read(q[i].l); read(q[i].r);
    		read(q[i].a); read(q[i].b);
    		q[i].o=i;
    	}
    	siz=sqrt(n);
    	sort(q+1,q+m+1,cmp);
    	rint head=1,tail=0;
    	for(i=1;i<=m;i++) {
    		while(head>q[i].l) Add(--head);
    		while(tail<q[i].r) Add(++tail);
    		while(head<q[i].l) Sub(head++);
    		while(tail>q[i].r) Sub(tail--);
    		q[i].ans1=C1.sum(q[i].b)-C1.sum(q[i].a-1);
    		q[i].ans2=C2.sum(q[i].b)-C2.sum(q[i].a-1);
    	}
    	sort(q+1,q+m+1,rule);
    	for(i=1;i<=m;i++) {
    		print(q[i].ans1); putc(' ');
    		print(q[i].ans2); putc('
    ');
    	}
    	return 0;
    }
    

    时间复杂度 (O((m+n)sqrt{n}logn+m(logn+logC)) (C为值域)

    (o2) 过的。

    值域分块

    #include<cmath>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    #define rint register int
    using namespace std;
    namespace FastIO
    {
    const int _SIZE = (1 << 21) + 1;
    char ibuf[_SIZE],obuf[_SIZE];
    char *iS,*iT;
    char c;
    char qu[55];
    char *oS=obuf,*oT=oS+_SIZE-1;
    bool _sign=false;
    int qr;
    // getchar
    #define gc() (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, _SIZE, stdin), (iS == iT ? EOF : *iS++)) : *iS++)
    // print the remaining part
    inline void flush() 
    {
        fwrite(obuf,1,oS-obuf,stdout);
        oS=obuf;
        return;
    }
    // putchar
    inline void putc(const char &x) 
    {
        *oS++=x;
        if(oS==oT)
            flush();
        return;
    }
    inline char getc()
    {
    	return gc();
    }
    // input a signed integer
    template <class T>
    inline void read(T &x) 
    {
    	x=0;
    	_sign=false;
        for (c=gc();c<'0'||c>'9';c=gc())
            if (c=='-')
                _sign=true;
        for (;c>='0'&&c<='9';c=gc()) 
    		x=(x<<1)+(x<<3)+(c&15);
        x=(_sign) ? (~x+1) : x;
        return;
    }
    // print a signed integer
    template <class T>
    inline void print(T x) {
        if (!x) {
        	putc('0');
        	return;
    	}
        if (x<0)
            putc('-'),x=~x+1;
        while(x) qu[++qr]=x%10+'0',x/=10;
        while(qr) putc(qu[qr--]);
        return;
    }
    // no need to call flush at the end manually!
    struct Flusher_ 
    {
        ~Flusher_() { flush(); }
    }io_flusher_;
    }  // namespace io
    using FastIO::read;
    using FastIO::print;
    using FastIO::putc;
    using FastIO::getc;
    //=================================================
    const int N=1e5+5;
    const int SQ=1e3+5;
    int n,m;
    int F[N];
    int L[SQ],R[SQ];
    int size,k;
    void Build()
    {
    	size=sqrt(N);
    	k=N/size+(N/size>0);
    	rint i,j;
    	for(i=1;i<=k;i++) {
    		L[i]=R[i-1]+1;
    		R[i]=i*size;
    	}
    	R[k]=N-1;
    	for(i=1;i<=k;i++) 
    		for(j=L[i];j<=R[i];j++) 
    			F[j]=i;
    	return;
    }
    struct Block
    {
    	int num[SQ];
    	int t[N];
    	inline void insert(const int &val)
    	{
    		t[val]++;
    		num[F[val]]++;
    		return;
    	}
    	inline void erase(const int &val)
    	{
    		t[val]--;
    		num[F[val]]--;
    		return;
    	}
    	inline int count(const int &l,const int &r)
    	{
    		rint i,res=0;
    		if(F[l]==F[r]) {
    			for(i=l;i<=r;i++) 
    				res+=t[i];
    			return res;
    		}
    		for(i=l;i<=R[F[l]];i++) 
    			res+=t[i];
    		for(i=F[l]+1;i<=F[r]-1;i++) 
    			res+=num[i];
    		for(i=L[F[r]];i<=r;i++) 
    			res+=t[i];
    		return res;
    	}
    }A,B;
    int a[N];
    struct quiz
    {
    	int l,r;
    	int a,b;
    	int ans1,ans2;
    	int o;
    }q[N];
    int siz;
    inline bool cmp(const quiz &a,const quiz &b)
    {
    	if(a.l/siz!=b.l/siz) 
    		return a.l<b.l;
    	else return a.r<b.r;
    }
    inline bool rule(const quiz &a,const quiz &b)
    {
    	return a.o<b.o;
    }
    inline void Add(int pos)
    {
    	if(A.count(a[pos],a[pos])==0)
    		B.insert(a[pos]);
    	A.insert(a[pos]);
    	return;
    }
    inline void Sub(int pos)
    {
    	if(A.count(a[pos],a[pos])==1) 
    		B.erase(a[pos]);
    	A.erase(a[pos]);
    	return;
    }
    int main()
    {
    //	freopen("1.in","r",stdin);
    	rint i;
    	read(n); read(m);
    	for(i=1;i<=n;i++) 
    		read(a[i]);
    	for(i=1;i<=m;i++) {
    		read(q[i].l); read(q[i].r);
    		read(q[i].a); read(q[i].b);
    		q[i].o=i;
    	}
    	Build();
    	siz=sqrt(n);
    	sort(q+1,q+m+1,cmp);
    	rint head=1,tail=0;
    	for(i=1;i<=m;i++) {
    		while(head>q[i].l) Add(--head);
    		while(tail<q[i].r) Add(++tail);
    		while(head<q[i].l) Sub(head++);
    		while(tail>q[i].r) Sub(tail--);
    		q[i].ans1=A.count(q[i].a,q[i].b);
    		q[i].ans2=B.count(q[i].a,q[i].b);
    	}
    	sort(q+1,q+m+1,rule);
    	for(i=1;i<=m;i++) {
    		print(q[i].ans1); putc(' ');
    		print(q[i].ans2); putc('
    ');
    	}
    	return 0;
    }
    

    时间复杂度:(O((n+m)sqrt{n}+msqrt{C}+mlogn))

    使用值域分块能达到复杂度的平衡。(指针移动 (O((n+m)sqrt{n})),求解 (O(msqrt{C}))

    写分块一定要记得特判最后一个块,

    k=N/size+(N/size>0);
    
    	R[k]=N-1;
    

    不然要么开太小了,要么越界。

  • 相关阅读:
    有关LinkedList常用方法的源码解析
    [Kotlin参考]一、总览-(7)多平台编
    [Kotlin参考]一、总览-(3)Kotlin for JavaScript
    [Kotlin参考]一、总览-(4)Kotlin原生
    [Kotlin参考]一、总览-(5)Kotlin数据科学
    [Kotlin参考]一、总览-(2)Android版Kotlin
    [Kotlin参考]一、总览-(1)服务器端Kotlin
    [Swift]LeetCode1312. 让字符串成为回文串的最少插入次数 | Minimum Insertion Steps to Make a String Palindrome
    [Swift]LeetCode1311. 获取你好友已观看的视频 | Get Watched Videos by Your Friends
    [Swift]LeetCode1310. 子数组异或查询 | XOR Queries of a Subarray
  • 原文地址:https://www.cnblogs.com/cjl-world/p/13170041.html
Copyright © 2011-2022 走看看