zoukankan      html  css  js  c++  java
  • [Codeforces]862F

    题目大意:n个字符串,支持修改一个位置上的字符串和查询一个区间的子区间中长度乘LCP的最大值,输入字符数和询问数不超过10^5。

    做法:求出相邻的LCP长度,区间LCP等于区间最小值,查询分几种情况考虑,一种只有一个串,线段树维护长度最大值即可;若有若干个串,设一个阈值k,若答案的LCP<=k,对于小等k的每一个i,若一个位置的相邻LCP大等i,设为1,否则设为0,即求区间最长连续1,每种i开一棵线段树维护即可;若LCP>k,我们把相邻LCP长度超过k的位置存进set,查询的时候拿出来,直接建笛卡尔树计算答案,由于字符总数有限,这样的位置不会超过L/k个。总时间复杂度为O(nklogn+nL/k),适当调整k,时间复杂度为O(n(nlogn)^0.5)。

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    #define MN 100000
    #define N 131072
    #define K 50
    struct node{int l,r,u,mx;}T[K+5][N*2+5];
    node operator+(const node&a,const node&b)
    {
        return (node){a.l+a.u*b.l,b.r+b.u*a.r,a.u*b.u,max(max(a.mx,b.mx),a.r+b.l)};
    }
    string s[MN+5];
    int t[N*2+5],v[MN+5],a[MN+5],an,Z[MN+5],zn,L[MN+5],R[MN+5],ans,S[MN+5];
    set<int> st;
    void change(int k,int x){for(t[k+=N]=x;k>>=1;)t[k]=max(t[k<<1],t[k<<1|1]);}
    int query(int l,int r)
    {
        int res=0;
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1)res=max(res,t[l+1]);
            if( r&1)res=max(res,t[r-1]);
        }
        return res;
    }
    void change(node*t,int k,node x){for(t[k+=N]=x;k>>=1;)t[k]=t[k<<1]+t[k<<1|1];}
    node Query(node*t,int l,int r)
    {
        node L,R;int ul=0,ur=0;
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1)L=ul?L+t[l+1]:(ul=1,t[l+1]);
            if( r&1)R=ur?t[r-1]+R:(ur=1,t[r-1]);
        }
        return ul?ur?L+R:L:R;
    }
    void renew(int x)
    {
        cin>>s[x];change(x,s[x].size());
        if(v[x]>K)st.erase(x);if(v[x+1]>K)st.erase(x+1);
        for(v[x]=0;v[x]<s[x].size()&&v[x]<s[x-1].size()&&s[x][v[x]]==s[x-1][v[x]];)++v[x];
        for(v[x+1]=0;v[x+1]<s[x].size()&&v[x+1]<s[x+1].size()&&s[x][v[x+1]]==s[x+1][v[x+1]];)++v[x+1];
        if(v[x]>K)st.insert(x);if(v[x+1]>K)st.insert(x+1);
        node a=(node){0,0,0,0},b=(node){1,1,1,1};
        for(int i=1;i<=K;++i)change(T[i],x,v[x]<i?a:b),change(T[i],x+1,v[x+1]<i?a:b);
    }
    void dfs(int x)
    {
        S[x]=1;
        if(L[x])dfs(L[x]),S[x]+=S[L[x]];
        if(R[x])dfs(R[x]),S[x]+=S[R[x]];
        ans=max(ans,v[x]*(S[x]+1));
    }
    int p(const set<int>::iterator&i){return i!=st.end()?*i:MN+1;}
    int main()
    {
        int n,m,i,l,r,z;
        n=read();m=read();
        for(i=1;i<=n;++i)renew(i);
        while(m--)
            if(read()==1)
            {
                l=read();r=read();
                ans=query(l,r);
                if(l<r)for(i=1;i<=K;++i)z=Query(T[i],l+1,r).mx,ans=max(ans,i*(z?z+1:0));
                set<int>::iterator it=st.upper_bound(l);
                for(z=p(it);z<=r;)
                {
                    for(a[an=1]=z;(z=p(++it))<=r&&z==a[an]+1;)a[++an]=z;
                    for(i=1,zn=0;i<=an;++i)
                    {
                        L[a[i]]=R[a[i]]=0;
                        while(zn&&v[a[i]]<v[a[Z[zn]]])L[a[i]]=a[Z[zn--]];
                        R[a[Z[zn]]]=a[i];Z[++zn]=i;
                    }
                    dfs(a[Z[1]]);
                }
                printf("%d
    ",ans);
            }
            else renew(read());
    }
  • 相关阅读:
    HDU-4248 A Famous Stone Collector 组合数学 DP
    HDU
    暑期训练1 Gym
    暑期训练1 Gym-102623L Lottery Tickets 模拟 贪心构造
    暑期训练2 Gym
    poj-1011 sticks(搜索题)
    hdu-2553 N皇后问题(搜索题)
    poj-2236 wireless network(并查集)
    poj-1700 crossing river(贪心题)
    poj-3278 catch that cow(搜索题)
  • 原文地址:https://www.cnblogs.com/ditoly/p/CF862F.html
Copyright © 2011-2022 走看看