• 分块总结


      尽管分块非常简单 但是它比其他数据结构更不好应用上去 。

    也就是说可以巧妙的采用分块的思想 来优化时间 一般都是将n 优化到sqrt(n);

    面对题目 我们总是会想办法转换模型 或者如果是一种算法的应用的话我们应该观察问题的特异性。

    这道题显然 如果求每个磁石能吸引的块数的话 这 不就是个二维偏序么 可是求总共能吸引的磁石个数。

    这就不太行了 二维偏序 当然也许可以暴力的时候写个二维偏序 拓扑序 bitset 或一下 最后 f[0].count()就是答案。

    复杂度是比较高的。那再转换模型 这不就是一个bfs吧。n^2的bfs超级好写。

    可是这个数据范围 卡爆bfs 想办法将其优化 我们把它按第一关键字排序分块 那么每次都会有一个界限 。

    这样我们只用管这个界限之前的就可以了,和这个界限之后的第一个块。再对每个块进行第二关键字排序。

    那么此时 每次第二关键字不满足就可以直接break 平均每次 被扫到均摊O(1)对于答案的选取。

    我建议直接统计答案不要用队列中的t 因为我不知道自己为什么会一直wa 我觉得没有任何的问题。。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<cctype>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<map>
    #include<vector>
    #include<ctime>
    #define INF 2147483646
    #define ll long long
    #define db double
    #define x(i) s[i].x
    #define y(i) s[i].y
    #define f(i) s[i].force
    #define m(i) s[i].m
    #define r(i) s[i].r
    #define dis(i) s[i].dis
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    inline void put(int x)
    {
        x<0?putchar('-'),x=-x:0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int MAXN=250002,maxn=1000;
    int n,c,p,s1,s2,T,len,ans;
    int q[MAXN],t,h;
    int l[maxn],r[maxn],flag[maxn],v[maxn],vis[MAXN];
    struct wy
    {
        int x,y;
        int m,force,r;
        double dis;
    }s[MAXN];
    inline double d(int t,int t1,int t2,int t3){return sqrt(((int)(t-t2)*(t-t2))*1.0+((int)(t1-t3)*(t1-t3))*1.0);}
    inline int cmp(wy x,wy y){return x.m<y.m;}
    inline double cmp1(wy x,wy y){return x.dis<y.dis;}
    void bfs()
    {
        t=1,h=0;
        while(++h<=t)
        {
            int last;
            if(h!=1)c=r(q[h]),p=f(q[h]);
            for(int i=1;i<=T;++i)
            {
                if(v[i]<=p)
                    for(int j=flag[i];j<=r[i];++j)
                    {
                        //if(vis[j]==1)continue;
                        if(dis(j)<=c){q[++t]=j,++flag[i];if(vis[j]==0)ans++,vis[j]=1;}
                        //直接统计答案为好 不然还是wa
                        else break;
                    }
                else {last=i;break;} 
            }
            for(int i=flag[last];i<=r[last];++i)
            {
                //if(vis[i]==1)continue;
                if(m(i)<=p)
                {    
                    if(dis(i)<=c)
                    {
                        q[++t]=i;
                        if(vis[i]==0)ans++,vis[i]=1;
                    }
                    else break;
                }
            }
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        s1=read();s2=read();
        p=read();c=read();
        n=read();
        for(int i=1;i<=n;++i)
        {
            x(i)=read();y(i)=read();
            m(i)=read();f(i)=read();
            r(i)=read();dis(i)=d(s1,s2,x(i),y(i));
        }
        sort(s+1,s+1+n,cmp);
        T=(int)sqrt(n*1.0);len=n/T;
        //for(int i=1;i<=n;i++)cout<<dis(i)<<endl;
        for(int i=1;i<=T;++i)
        {
            l[i]=(i-1)*len+1;
            r[i]=len*i;
            flag[i]=l[i];
            v[i]=m(r[i]);
            sort(s+l[i],s+r[i]+1,cmp1);
        }
        if(r[T]<n)
        {
            ++T,l[T]=r[T-1]+1,r[T]=n;
            v[T]=m(r[T]);
            sort(s+l[T],s+r[T]+1,cmp1);
            flag[T]=l[T];
        }
        //for(int i=1;i<=n;i++)cout<<dis(i)<<' '<<m(i)<<' '<<f(i)<<' '<<r(i)<<endl;
        bfs();
        put(ans);
        return 0;
    }
    View Code

    这道题是书上讲的 用分块进行分治 这种分治答案非常的典型 也是很多用不了单调队列的题目优化的模型方法之一非常值得借鉴。

    直接把n^2的算法利用单调性优化到nsqrt(n)这样 成功完美解决一道莫队的题目!

    记得以前写的维护一些区间的性质 例如求某个区间的最大值ST算法。。

    当时我是用单调队列扫 然后发现一个另一个端点不具单调性 此时我们可以也是这道题的解法:

    将其按照第一关键字排序 然后 分块 分成 sqrt(m) 块的大小为sqrt(m) 

    对于每个块中的元素 我们按照第二关键字排序对于每个块之中 第二关键字是单调递增的。

    第一关键字 每次改变幅度是sqrt(n)的 考虑如果不是根号n的 那么也影响不大 复杂度 nsqrt(n).

    至于每次第二关键字的变化幅度一定是 sqrt(n)的 不懂的话 我用了反证法证明这个问题。

    关键是 均摊复杂度 非常优秀 nsqrt(n) 还有很关键的是 每次选择的基准块很不错导致复杂度骤降。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<cctype>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<map>
    #include<vector>
    #include<ctime>
    #define INF 2147483646
    #define ll long long
    #define db double
    #define x(i) t[i].x
    #define y(i) t[i].y
    #define id(i) t[i].id
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline ll read()
    {
        ll x=0,f=1;char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    inline void put(ll x)
    {
        x<0?putchar('-'),x=-x:0;
        ll num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        return;
    }
    const ll MAXN=50002;
    struct wy
    {
        ll x,y;
        ll id;
    }t[MAXN];
    ll n,m,T,len,num;
    ll x[MAXN],y[MAXN],l[MAXN],r[MAXN];
    ll a[MAXN],cnt[MAXN],ans;// molecular 分子  denominator分母
    ll cmp(wy x,wy y){return x.x<y.x;}
    ll cmp1(wy x,wy y){return x.y<y.y;}
    ll cmp2(wy x,wy y){return x.id<y.id;}
    ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
    void curculate()
    {
        for(ll k=1;k<=T;++k)
        {
            ans=0;
            memset(cnt,0,sizeof(cnt));
            ll R=y(l[k]),L=x(l[k]);//右端点单调递增
            for(ll i=L;i<=R;++i)
            {
                ++cnt[a[i]];
                if(cnt[a[i]]>1)ans=ans-(cnt[a[i]]-1)*(cnt[a[i]]-2)/2+cnt[a[i]]*(cnt[a[i]]-1)/2;
            }
            x[id(l[k])]=ans;
            for(ll i=l[k]+1;i<=r[k];++i)
            {
                if(x(i)==y(i)){x[id(i)]=0;continue;}
                if(R<y(i))
                    for(ll j=R+1;j<=y(i);++j)
                    {
                        ++cnt[a[j]];
                        if(cnt[a[    j]]>1)ans=ans-(cnt[a[j]]-1)*(cnt[a[j]]-2)/2+cnt[a[j]]*(cnt[a[j]]-1)/2;
                    }
                if(L<x(i))
                    for(ll j=L;j<x(i);++j)
                    {
                        --cnt[a[j]];
                        if(cnt[a[j]]>0)ans=ans-(cnt[a[j]]+1)*cnt[a[j]]/2+cnt[a[j]]*(cnt[a[j]]-1)/2;
                    }
                if(L>x(i))
                    for(ll j=L-1;j>=x(i);--j)
                    {
                        ++cnt[a[j]];
                        if(cnt[a[j]]>1)ans=ans-(cnt[a[j]]-1)*(cnt[a[j]]-2)/2+cnt[a[j]]*(cnt[a[j]]-1)/2;
                    }
                x[id(i)]=ans;
                L=x(i);R=y(i);
            }
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        n=read();m=read();
        for(ll i=1;i<=n;++i)a[i]=read();
        for(ll i=1;i<=m;++i)
        { 
            x(i)=read();
            y(i)=read();
            id(i)=i;
        }
        sort(t+1,t+1+m,cmp);
        T=(ll)sqrt(m*1.0);len=m/T;
        for(ll i=1;i<=T;++i)
        {
            l[i]=(i-1)*len+1;
            r[i]=len*i;
            sort(t+l[i],t+r[i]+1,cmp1);
        }
        if(r[T]<m)
        {
            ++T,l[T]=r[T-1]+1,r[T]=m;
            sort(t+l[T],t+r[T]+1,cmp1);
        }
        curculate();
        sort(t+1,t+1+m,cmp2);
        for(ll i=1;i<=m;i++)
        {
            if(x[i]==0)puts("0/1");
            else 
            {
                ll w=(y(i)-x(i)+1)*(y(i)-x(i))/2;
                ll g=gcd(w,x[i]);
                put(x[i]/g),putchar('/'),put(w/g),puts("");
            }
        }
        return 0;
    }
    View Code

  • 相关阅读:
    今年要读的书
    java多线程
    json-lib 使用教程
    tomcat原理
    静态long类型常量serialVersionUID的作用
    使用junit4测试Spring
    MySQL各版本的区别
    spring mvc 下载安装
    hibernate、struts、spring mvc的作用
    【面试】hibernate n+1问题
  • 原文地址:https://www.cnblogs.com/chdy/p/10533163.html
Copyright © 2020-2023  润新知