codechef TASUFFIX

题意:

设数组 A[i] = i,大小为 n,对其进行 m 次操作,有两种操作:
1. 把某一段提到开头
2. 区间翻转
所有操作结束后询问后缀数组的 rank sa数组为 A 的字符串 S有多少种可能
S 的限制是字符串中出现的都是正整数,且最大元素等于不同的元素个数
n109,m105 n ≤ 10 9 , m ≤ 10 5

题解:

先吐槽,这题调了几天几夜,后来发现原来sa数组。
所以 因为懒 我将sa转成rank来做。
首先splay维护哪个东西。
考虑rank从小到大填入数字,显然,当前填的数字一定大于等于上一位填的数字。
什么时候能相等呢,条件就是 rank[sa[i]+1]<rank[sa[i+1]+1] r a n k [ s a [ i ] + 1 ] < r a n k [ s a [ i + 1 ] + 1 ]
假如在一段连续的区间一定是满足条件的,边界的情况单独处理即可。
code:

#include<map>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int mod=1e9+7;
map<int,int> mp;
struct trnode{
    int son[2],fa,l,r,rev,c;
}tr[400010];int tot=0,root;
int L,R,t;
int getnum(int x){return abs(tr[x].r-tr[x].l)+1;}
void update(int x)
{
    int lc=tr[x].son[0],rc=tr[x].son[1];
    tr[x].c=tr[lc].c+tr[rc].c+getnum(x);
    if(tr[x].rev)
    {
        swap(tr[lc].l,tr[lc].r);swap(tr[rc].l,tr[rc].r);
        swap(tr[x].son[0],tr[x].son[1]);
        tr[lc].rev^=1;tr[rc].rev^=1;tr[x].rev=0;
    }
}
struct node{
    int l,r,L,R;
}a[400010],b[400010];int num=0;
void dfs(int x)
{
    if(!x) return;
    update(x);
    dfs(tr[x].son[0]);
    b[++num].l=tr[x].l;b[num].r=tr[x].r;
    dfs(tr[x].son[1]);
}
void pushup(int x)
{
    update(x);
    if(tr[x].fa) pushup(tr[x].fa);
}
void pushdown(int x)
{
    if(tr[x].fa) pushdown(tr[x].fa);
    update(x);
}
void rotate(int x)
{
    int y=tr[x].fa,z=tr[y].fa,w,R,r;
    w=(tr[y].son[0]==x);
    R=y;r=tr[x].son[w];tr[R].son[1-w]=r;if(r) tr[r].fa=R;
    R=z;r=x;tr[R].son[tr[z].son[1]==y]=r;tr[r].fa=R;
    R=x;r=y;tr[R].son[w]=r;tr[r].fa=R;
    update(y);update(x);
}
void splay(int x,int fa)
{
    pushdown(x);
    while(tr[x].fa!=fa)
    {
        int y=tr[x].fa,z=tr[y].fa;
        if(z==fa) rotate(x);
        else
        {
            if((tr[y].son[0]==x)==(tr[z].son[0]==y)) rotate(y),rotate(x);
            else rotate(x),rotate(x);
        }
    }
    if(fa==0) root=x;
}
int find_x(int k)
{
    int x=root;t=0;
    while(1)
    {
        update(x);
        int lc=tr[x].son[0],rc=tr[x].son[1];
        L=t+tr[lc].c+1;R=L+getnum(x)-1;
        if(k<=tr[lc].c) x=lc;
        else if(k>tr[lc].c+getnum(x)) k-=tr[lc].c+getnum(x),t+=tr[lc].c+getnum(x),x=rc;
        else break;
    }
    L--;R--;
    return x;
}
int div_r(int x,int k)
{
    if(k==L) return x;
    int p=++tot;
    if(tr[x].l<=tr[x].r)
    {
        tr[p].l=tr[x].r-(R-k);tr[p].r=tr[x].r;
        tr[x].r=tr[p].l-1;
    }
    else
    {
        tr[p].l=tr[x].r+(R-k);tr[p].r=tr[x].r;
        tr[x].r=tr[p].l+1;
    }
    tr[p].son[1]=tr[x].son[1];tr[x].son[1]=0;
    tr[p].fa=tr[x].fa;tr[x].fa=p;tr[p].son[0]=x;
    tr[tr[p].fa].son[tr[tr[p].fa].son[1]==x]=p;
    if(tr[p].son[1]) tr[tr[p].son[1]].fa=p;
    update(x);update(p);
    if(root==x) root=p;
    return p;
}
int div_l(int x,int k)
{
    if(k==R) return x;
    int p=++tot;
    if(tr[x].l<=tr[x].r)
    {
        tr[p].r=tr[x].l+(k-L);tr[p].l=tr[x].l;
        tr[x].l=tr[p].r+1;
    }
    else
    {
        tr[p].r=tr[x].l-(k-L);tr[p].l=tr[x].l;
        tr[x].l=tr[p].r-1;
    }
    tr[p].son[0]=tr[x].son[0];tr[x].son[0]=0;
    tr[p].fa=tr[x].fa;tr[x].fa=p;tr[p].son[1]=x;
    tr[tr[p].fa].son[tr[tr[p].fa].son[1]==x]=p;
    if(tr[p].son[0]) tr[tr[p].son[0]].fa=p;
    update(x);update(p);
    if(root==x) root=p;
    return p;
}
void solve(int l,int r)
{
    int x=find_x(l);x=div_l(x,l-1);
    int y=find_x(r+2);y=div_r(y,r+1);
    splay(x,0);splay(y,x);
}
int n,m;
void add(int l,int r,int fa,int d)
{
    int x=++tot;
    tr[x].l=l;tr[x].r=r;tr[x].fa=fa;
    tr[fa].son[d]=x;tr[x].c=r-l+1;
    pushup(x);
}
LL pow(LL a,int b)
{
    LL ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;b>>=1;
    }
    return ans;
}
bool cmp(node a,node b) {return a.l<b.l;}
bool cmp_L(node a,node b) {return a.L<b.L;}
int get_next(int k,int x,int op)
{
    if(x==n) return 0;
    return mp[x+1]?mp[x+1]:k+op;
}
int main()
{
    scanf("%d %d",&n,&m);
    root=tot=1;tr[1].l=0;tr[1].r=0;tr[1].c=0;
    add(n+1,n+1,1,1);add(1,n,2,0);
    while(m--)
    {
        int op,l,r;scanf("%d %d %d",&op,&l,&r);
        if(op==1)
        {
            solve(l,r);
            int x=tr[tr[root].son[1]].son[0];
            swap(tr[x].l,tr[x].r);tr[x].rev^=1;
        }
        else
        {
            if(l!=1)
            {
                solve(l,r);
                int x=tr[tr[root].son[1]].son[0],y=tr[root].son[1];
                tr[x].fa=0;tr[y].son[0]=0;pushup(y);
                solve(1,1);y=tr[tr[root].son[1]].son[0];
                pushdown(y);
                tr[y].son[0]=x;tr[x].fa=y;pushup(x);
            }
        }
    }
    num=-1;dfs(root);
    int now=0,ans=0;
    for(int i=1;i<num;i++)
    {
        now++;int L=now,R=now+abs(b[i].r-b[i].l);now+=abs(b[i].r-b[i].l);
        if(b[i].l>b[i].r) swap(b[i].l,b[i].r),swap(L,R);
        a[i].l=L;a[i].r=R;a[i].L=b[i].l;a[i].R=b[i].r;
    }
    sort(a+1,a+num,cmp_L);a[num].l=0;
    for(int i=1;i<num;i++)
    {
        ans+=max(abs(a[i].r-a[i].l)-1,0);
        if(abs(a[i].r-a[i].l)>=1)
        {
            if(a[i].l<a[i].r) ans+=(a[i+1].l>a[i].r);
            if(a[i].l>a[i].r) ans+=(a[i+1].l<a[i].r);
        }
    }
    for(int i=1;i<num;i++) mp[a[i].L]=a[i].l,mp[a[i].R]=a[i].r;
    sort(a+1,a+num,cmp);
    for(int i=1;i<num-1;i++)
    {
        if(a[i].l<=a[i].r)
        {
            if(a[i+1].l<=a[i+1].r) ans+=(get_next(a[i+1].l,a[i+1].L,1)>mp[a[i].R+1]);
            else ans+=(mp[a[i+1].R+1]>mp[a[i].R+1]);
        }
        else
        {
            if(a[i+1].l<=a[i+1].r) ans+=(get_next(a[i+1].l,a[i+1].L,1)>get_next(a[i].l,a[i].L,-1));
            else ans+=(mp[a[i+1].R+1]>get_next(a[i].l,a[i].L,-1));
        }
    }
    printf("%lld",pow(2,ans));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值