• BZOJ4358: permu


    Description

    给出一个长度为n的排列P(P1,P2,...Pn),以及m个询问。每次询问某个区间[l,r]中,最长的值域
    连续段长度。

    Input

    第一行两个整数n,m。
    接下来一行n个整数,描述P。
    接下来m行,每行两个整数l,r,描述一组询问。

    Output

    对于每组询问,输出一行一个整数,描述答案。

    Sample Input

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

    Sample Output

    3
    3
    4

    HINT

    对于询问[1,4],P2,P4,P1组成最长的值域连续段[1,3];

    对于询问[5,8],P8,P5,P7组成最长的值域连续段[4,6];

    对于询问[1,7],P5,P7,P3,P6组成最长的值域连续段[5,8]。

    1<=n,m<=50000
     
    首先O(N^1.5*logN)的莫队套线段树做法应该是谁都会的。
    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=50010;
    int n,m,A[maxn],bl[maxn],ans[maxn];
    struct Query {
        int l,r,id;
        bool operator < (const Query& ths) const {
            if(bl[l]==bl[ths.l]) return r<ths.r;
            return l<ths.l;
        }
    }Q[maxn];
    int maxv[maxn*3],lsum[maxn*3],rsum[maxn*3];
    void update(int o,int l,int r,int pos,int v) {
        if(l==r) maxv[o]=lsum[o]=rsum[o]=v;
        else {
            int lc=o<<1,rc=lc|1,mid=l+r>>1;
            if(pos<=mid) update(lc,l,mid,pos,v);
            else update(rc,mid+1,r,pos,v);
            lsum[o]=lsum[lc]==mid-l+1?lsum[lc]+lsum[rc]:lsum[lc];
            rsum[o]=rsum[rc]==r-mid?rsum[rc]+rsum[lc]:rsum[rc];
            maxv[o]=max(maxv[lc],maxv[rc]);
            maxv[o]=max(maxv[o],lsum[rc]+rsum[lc]);
        }
    }
    void del(int v) {
        update(1,1,n,v,0);
    }
    void add(int v) {
        update(1,1,n,v,1);
    }
    int main() {
        n=read();m=read();int SIZE=(int)sqrt(n);
        rep(i,1,n) A[i]=read(),bl[i]=(i-1)/SIZE+1;
        rep(i,1,m) Q[Q[i].id=i].l=read(),Q[i].r=read();
        sort(Q+1,Q+m+1);
        int l=1,r=0;
        rep(i,1,m) {
            while(l>Q[i].l) add(A[--l]);
            while(r<Q[i].r) add(A[++r]);
            while(l<Q[i].l) del(A[l++]);
            while(r>Q[i].r) del(A[r--]);
            ans[Q[i].id]=maxv[1];
        }
        rep(i,1,m) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

    然而T飞了(听说有常数帝硬是卡过去了)

    为什么要带一个log呢?因为有删除操作。

    那么如果只有添加没有删除呢?我们可以用O(1)的并查集来做。

    那么我们可以考虑改造一下莫队算法,考虑不移动左端点,而暴力计算左边的一段对答案的影响,右端用O(1)的并查集来做就可以了。

    前者操作可以再用一个并查集,注意实现细节。

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=50010;
    int n,m,A[maxn],bl[maxn],en[maxn],ans[maxn];
    struct Query {
        int l,r,id;
        bool operator < (const Query& ths) const {
            if(bl[l]==bl[ths.l]) return r<ths.r;
            return l<ths.l;
        }
    }Q[maxn];
    int findset(int* pa,int x) {return pa[x]==x?x:pa[x]=findset(pa,pa[x]);}
    int pa[maxn],s[maxn],vis[maxn],nowans;
    void add(int u) {
        int v;s[u]=1;pa[u]=u;
        if(v=findset(pa,u-1)) pa[v]=u,s[u]+=s[v];
        if(v=findset(pa,u+1)) pa[v]=u,s[u]+=s[v];
        nowans=max(nowans,s[u]);
    }
    int pa2[maxn],mx[maxn],mn[maxn],S[maxn],top;
    void add2(int u,int& res) {
        int v;pa2[u]=u;mx[u]=mn[u]=u;S[++top]=u;
        if(v=findset(pa2,u-1)) mn[u]=mn[v];
        else if(v=findset(pa,u-1)) mn[u]-=s[v];
        if(v=findset(pa2,u+1)) mx[u]=mx[v];
        else if(v=findset(pa,u+1)) mx[u]+=s[v];
        res=max(res,mx[u]-mn[u]+1);
        S[++top]=mx[u];pa2[mx[u]]=u;
        S[++top]=mn[u];pa2[mn[u]]=u;
    }
    int main() {
        n=read();m=read();int SIZE=(int)sqrt(n);
        rep(i,1,n) A[i]=read(),bl[i]=(i-1)/SIZE+1,en[bl[i]]=i;
        rep(i,1,m) Q[Q[i].id=i].l=read(),Q[i].r=read();
        sort(Q+1,Q+m+1);
        rep(i,1,m) {
            int p=i,cur;nowans=0;
            while(bl[Q[p].l]==bl[Q[i].l]&&p<=m) p++;
            memset(pa,0,sizeof(pa));
            cur=en[bl[Q[i].l]];
            rep(j,i,p-1) {
                while(cur<Q[j].r) add(A[++cur]);
                ans[Q[j].id]=nowans;
                rep(k,Q[j].l,min(Q[j].r,en[bl[Q[i].l]])) add2(A[k],ans[Q[j].id]);
                while(top) pa2[S[top--]]=0;
            }
            i=p-1;
        }
        rep(i,1,m) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    monkeyrunner 进行多设备UI测试
    python Pool并行执行
    python 字符串函数
    python Map()和reduce()函数
    python re模块使用
    3.6 C++继承机制下的构造函数
    3.5 C++间接继承
    3.4 C++名字隐藏
    3.3 C++改变基类成员在派生类中的访问属性
    3.2 C++继承方式
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5070914.html
Copyright © 2020-2023  润新知