zoukankan      html  css  js  c++  java
  • Luogu5284 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)

      先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可。场上就写了这个。

      100分也没有什么本质区别,没有A串长度不小于B串的性质后,区间连边变成了矩形连边,用主席树或KDTree优化连边即可,当然主席树会更靠谱,这里写了KDTree,在loj上T掉了。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define N 200010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int T,n,na,nb,m;
    char s[N];
    int rk[N<<1],tmp[N<<1],sa[N],sa2[N],Cnt[N],h[N],f[N][20],LG2[N];
    struct data{int l,r,i;
    }a[N],b[N];
    void make()
    {
        int m=26;
        memset(Cnt,0,sizeof(Cnt));
        memset(rk,0,sizeof(rk));
        memset(tmp,0,sizeof(tmp));
        for (int i=1;i<=n;i++) Cnt[rk[i]=(s[i]-'a'+1)]++;
        for (int i=1;i<=m;i++) Cnt[i]+=Cnt[i-1];
        for (int i=n;i>=1;i--) sa[Cnt[rk[i]]--]=i;
        for (int k=1;k<=n;k<<=1)
        {
            int p=0;
            for (int i=n-k+1;i<=n;i++) sa2[++p]=i;
            for (int i=1;i<=n;i++) if (sa[i]>k) sa2[++p]=sa[i]-k;
            for (int i=1;i<=m;i++) Cnt[i]=0;
            for (int i=1;i<=n;i++) Cnt[rk[i]]++;
            for (int i=1;i<=m;i++) Cnt[i]+=Cnt[i-1];
            for (int i=n;i>=1;i--) sa[Cnt[rk[sa2[i]]]--]=sa2[i];
            for (int i=1;i<=n*2;i++) tmp[i]=rk[i];
            p=1,rk[sa[1]]=1;
            for (int i=2;i<=n;i++)
            {
                if (tmp[sa[i]]!=tmp[sa[i-1]]||tmp[sa[i]+k]!=tmp[sa[i-1]+k]) p++;
                rk[sa[i]]=p;
            }
            m=p;if (m==n) break;
        }
        for (int i=1;i<=n;i++)
        {
            h[i]=max(h[i-1]-1,0);
            while (s[i+h[i]]==s[sa[rk[i]-1]+h[i]]) h[i]++;
        }
        for (int i=1;i<=n;i++) f[i][0]=h[sa[i]];
        for (int j=1;j<20;j++)
            for (int i=1;i<=n;i++)
            f[i][j]=min(f[i][j-1],f[min(n,i+(1<<j-1))][j-1]);
    }
    int query(int x,int y)
    {
        x++;if (x>y) return N;
        return min(f[x][LG2[y-x+1]],f[y-(1<<LG2[y-x+1])+1][LG2[y-x+1]]);
    }
    int root,cnt,p[N<<1],degree[N<<1],q[N<<1],val[N<<1],t;
    ll F[N<<1];
    struct data2{int to,nxt;
    }edge[N<<9];
    struct data3{int l,r,x,y,ch[2],i;
    }tree[N<<1];
    void addedge(int x,int y){t++;degree[y]++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    ll topsort()
    {
        int head=0,tail=0;
        for (int i=1;i<=cnt;i++)
        {
            F[i]=val[i];
            if (!degree[i]) q[++tail]=i;
        }
        while (head<tail)
        {
            int x=q[++head];
            for (int i=p[x];i;i=edge[i].nxt)
            {
                degree[edge[i].to]--;
                F[edge[i].to]=max(F[edge[i].to],F[x]+val[edge[i].to]);
                if (!degree[edge[i].to]) q[++tail]=edge[i].to;
            }
        }
        if (tail<cnt) return -1;
        ll ans=0;
        for (int i=1;i<=cnt;i++) ans=max(ans,F[i]);
        return ans;
    }
    int newnode(){cnt++;p[cnt]=degree[cnt]=val[cnt]=F[cnt]=0;return cnt;}
    bool cmp1(const data&a,const data&b)
    {
        return a.l<b.l||a.l==b.l&&a.r<b.r;
    }
    bool cmp2(const data&a,const data&b)
    {
        return a.r<b.r||a.r==b.r&&a.l<b.l;
    }
    bool cmp3(const data&a,const data&b)
    {
        return a.i<b.i;
    }
    void build(int &k,int l,int r)
    {
        if (l>r) return;
        k=newnode();
        int mid=l+r>>1;
        bool flag;
        /*if (rand()&1)
        {
            long double s1=0,s2=0,u=0,v=0;
            for (int i=l;i<=r;i++) s1+=1ll*a[i].l*a[i].l,s2+=a[i].l;
            u=s1-s2/(r-l+1)*s2;s1=0,s2=0;
            for (int i=l;i<=r;i++) s1+=1ll*a[i].r*a[i].r,s2+=a[i].r;
            v=s1-s2/(r-l+1)*s2;
            flag=u>v;
        }
        else*/
        {
            int u=a[l].l,v=a[l].l,w;
        	for (int i=l;i<=r;i++) u=min(u,a[i].l),v=max(v,a[i].l);
        	w=v-u;
        	u=a[l].r,v=a[l].r;for (int i=l;i<=r;i++) u=min(u,a[i].r),v=max(v,a[i].r);
        	flag=v-u<w;
        }
        if (flag) nth_element(a+l,a+mid,a+r+1,cmp1);
        else nth_element(a+l,a+mid,a+r+1,cmp2);
        tree[k].i=a[mid].i;
        tree[k].l=tree[k].r=a[mid].l;
        tree[k].x=tree[k].y=a[mid].r;
        tree[k].ch[0]=tree[k].ch[1]=0;
        for (int i=l;i<=r;i++)
        {
            tree[k].l=min(tree[k].l,a[i].l);
            tree[k].r=max(tree[k].r,a[i].l);
            tree[k].x=min(tree[k].x,a[i].r);
            tree[k].y=max(tree[k].y,a[i].r);
        }
        build(tree[k].ch[0],l,mid-1);
        build(tree[k].ch[1],mid+1,r);
        if (tree[k].ch[0]) addedge(k,tree[k].ch[0]);
        if (tree[k].ch[1]) addedge(k,tree[k].ch[1]);
        addedge(k,tree[k].i);
    }
    void cnnct(int k,int l,int r,int x,int y,int p)
    {
        if (!k||l>tree[k].r||r<tree[k].l||x>tree[k].y||y<tree[k].x) return;
        if (l<=tree[k].l&&r>=tree[k].r&&x<=tree[k].x&&y>=tree[k].y) {addedge(p,k);return;}
        if (l<=a[tree[k].i].l&&r>=a[tree[k].i].l&&x<=a[tree[k].i].r&&y>=a[tree[k].i].r) addedge(p,tree[k].i);
        cnnct(tree[k].ch[0],l,r,x,y,p);
        cnnct(tree[k].ch[1],l,r,x,y,p);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        T=read();srand(time(0));
        for (int i=2;i<=200000;i++)
        {
            LG2[i]=LG2[i-1];
            if ((2<<LG2[i])<=i) LG2[i]++;
        }
        while (T--)
        {
            scanf("%s",s+1);
            n=strlen(s+1);
            make();
            na=read();
            for (int i=1;i<=na;i++)
            {
                a[i].l=read(),a[i].r=read(),a[i].i=i;
                a[i].r=a[i].r-a[i].l+1,a[i].l=rk[a[i].l];
            }
            nb=read();
            for (int i=1;i<=nb;i++)
            {
                b[i].l=read(),b[i].r=read(),b[i].i=b[i].r-b[i].l+1;
                int x=rk[b[i].l];b[i].l=b[i].r=x;
                int l=1,r=x;
                while (l<=r)
                {
                    int mid=l+r>>1;
                    if (query(mid,x)>=b[i].i) b[i].l=mid,r=mid-1;
                    else l=mid+1;
                }
                l=x,r=n;
                while (l<=r)
                {
                    int mid=l+r>>1;
                    if (query(x,mid)>=b[i].i) b[i].r=mid,l=mid+1;
                    else r=mid-1;
                }
            }
            for (int i=1;i<=na;i++) F[i]=degree[i]=p[i]=0,val[i]=a[i].r;t=0;cnt=na;
            build(root,1,na);sort(a+1,a+na+1,cmp3);
            m=read();
            for (int i=1;i<=m;i++)
            {
                int x=read(),y=read();
                cnnct(root,b[y].l,b[y].r,b[y].i,n,x);
            }
            cout<<topsort()<<endl;
        }
        return 0;
    }
    

      更好的做法是直接对给出的A串按字典序排序,显然也可以通过SA做到,这样同样用线段树优化连边即可。因为没有什么本质区别就不写了。

  • 相关阅读:
    zabbix 设备(自己的实践)
    10.24的注意事项——解决linux_jni编译错误的问题
    [Angular] Adding keyboard events to our control value accessor component
    [tmux] Copy and paste text from a tmux session
    [tmux] Customize tmux with tmux.conf
    [tmux] Zoom and resize to view a particular pane within tmux
    [tmux] Manage terminal workspaces using session naming
    [tmux] Reuse terminal workspaces using tmux sessions
    [tmux] Create collections of panes using tmux windows
    [tmux] Organize your terminal using tmux panes
  • 原文地址:https://www.cnblogs.com/Gloid/p/10679719.html
Copyright © 2011-2022 走看看