zoukankan      html  css  js  c++  java
  • zm吃包子

    【题目背景】:
    zm 喜欢上了吃包子。
    【题面描述】:
    zm 每天都要去买包子,但是为了减肥,zm 设置了一系列规则来控制他每天买包子的数量。
    他随机了 n 个特殊字符串,然后用 n 个字符串来衡量接下来 Q 天每天该买多少个包子。
    规则如下:
    1.每天 zm 会生成两个字符串,他把一串称为 A 串,另一串称为 B 串。
    2. 此时每个特殊字符串有一个值 F[i],当 A 串为第 i 个特殊字符串的前缀且 B 串为第i 个字符串的后缀时(可重叠),F[i]=1,否则 F[i]=0。
    3.如果 F[i]当前等于 1,那么说明 zm 要买这个包子。zm 每天晚上会做一个梦,梦里会出现一个数字 K,zm 觉得这个数字不吉利,就想把他买的编号第 K 小的包子给 zackzh,于是 zm 就想知道这个包子的编号。zm 觉得这个问题对他来说太简单了,于是找到了你,让你代他写一个程序解决这个问题。
    【输入格式】:
    输入到文件 zmchibaozi.in。
    第一行包含两个数 n,Q。接下来 n 行,每一行表示一个特殊字符串。接下来 Q 行,每一行表示这一天 zm 生成的 A 串,B 串和 K。
    【输出格式】:
    输出到文件 zmchibaozi.out。共 Q 行,每一行表示这一天 zm 买的编号第 K 小的包子,若无解则输出-1。
    【样例输入】:
    3 6
    aaaaa
    abacabaa
    avtobus
    a a 1
    a aa 2
    aa a 2
    aaaaa aaaa 1
    abac caba 3
    abac a 1
    【样例输出】:
    1
    2
    -1
    1
    -1
    2
    【数据范围】:
    用 s1 表示特殊字符串总长度,s2 表示 A 串总长度,s3 表示 B 串总长度。
    对于 10%的数据,s1,s2,s3<=5000。
    有另外 10%的数据,所有的 A 串一样。
    有另外 10%的数据,所有的 B 串一样。
    有另外 30%的数据,每个 A 串和 B 串的长度均小于 20 且 n<=10000。
    对于 100%的数据,s1<=1000000,s2,s3<=2000000,K<=n,m<=100000,所有字符串都小写。
    【题目解析】
    首先可以将所有特殊字符串按正反建两颗trie树,这样之后每次询问时找到A,B串在这两颗trie上的节点位置,那么答案就是这两个节点的子树中共有的节点编号第K大的节点。
    可以继续抽象模型。
    一个节点在这个子树内就是它的dfn在根的dfn和dfn+siz-1之间。
    那么可以得到这样一个问题
    图中x表示正trie的dfn,y表示反trie的dfn。
    将每个特殊串变为一个点(正向trie的dfn,反向trie的dfn)。
    将每个询问两个子树中共有点的第K大转化为求矩形中第K大的点。
    问题便转化为经典的整体二分。
    使用扫描线求解。
    代码如下:
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+5;
    int n,q,size,ans[N],ge,cnt1,cnt2,sh[N],dq[N],dui[N],cj,cc[N];
    struct ztef
    {
        int x1,x2,y1,y2,k,id;
    }a[N<<1],huan2[N];
    struct cha
    {
        int qi,ho;
    }b[N],huan[N];
    struct line
    {
        int he,ze1,ze2,pu,du;
    }li[N<<1];
    string s,ss;
    struct pigu
    {
        int er[N][27],dfn[N],cnt,siz[N];
        inline int insert(string x)
        {
            int len=x.size(),now=0;
            for(int i=0;i<len;i++)
            {
                if(!er[now][x[i]-'a']) er[now][x[i]-'a']=++cnt;
                now=er[now][x[i]-'a'];
            }
            return now;
        }
        inline void dfs(int now)
        {
            dfn[now]=++size;siz[now]=1;
            for(int i=0;i<=25;i++)
            {
                if(!er[now][i]) continue;
                dfs(er[now][i]);
                siz[now]+=siz[er[now][i]];
            }
        }
        inline int cha(string x)
        {
            int now=0,len=x.size();
            for(int i=0;i<len;i++)
            {
                if(!er[now][x[i]-'a']) return 0;
                 now=er[now][x[i]-'a'];
            }
            return now;
        }
    }zh,fa;
    inline int read()
    {
        char c=getchar();
        int x=0,f=1;
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    inline void update(int now,int v)
    {
        while(now<=cj)
        {
            sh[now]+=v;
            now+=lowbit(now);
        }
    }
    inline int query(int now)
    {
        int daan=0;
        if(now<=0) return 0;
        while(now)
        {
            daan+=sh[now];
            now-=lowbit(now);
        }
        return daan;
    }
    inline bool cmp2(line x,line y)
    {
        return x.he<y.he;
    }
    inline bool cmp1(cha x,cha y)
    {
        return x.qi<y.qi;
    }
    inline void solve(int l,int r,int L,int R)
    {
        if(L>R) return;
        if(l==r)
        {
            if(r==n+1) for(int i=L;i<=R;i++) ans[dui[i]]=-1;
            else for(int i=L;i<=R;i++) ans[dui[i]]=l;
            return;
        }
        int cn3=1,mid=(l+r)>>1,cn1=0,cn2=0;
        for(int i=l;i<=mid;i++)
            huan[++cn1]=b[i];
        sort(huan+1,huan+cn1+1,cmp1);
        for(int i=L;i<=R;i++)
        {
            if(ans[dui[i]]==-1) continue;
            li[++cn2]=(line){a[dui[i]].x1-1,a[dui[i]].y1,a[dui[i]].y2,-1,i};
            li[++cn2]=(line){a[dui[i]].x2,a[dui[i]].y1,a[dui[i]].y2,1,i};
        }
        sort(li+1,li+cn2+1,cmp2);
        for(int i=1;i<=cn2;i++)
        {
            while(cn3<=cn1&&huan[cn3].qi<=li[i].he)
            {
                update(huan[cn3].ho,1);
                cn3++;
            }
            dq[li[i].du]+=(query(li[i].ze2)-query(li[i].ze1-1))*li[i].pu;
        }
        for(int i=1;i<cn3;i++)
            update(huan[i].ho,-1);
        int hu1=L,hu2=R;
        for(int i=L;i<=R;i++)
        {
            if(dq[i]>=a[dui[i]].k)
                cc[hu1++]=dui[i];
            else
            {
                cc[hu2--]=dui[i];
                a[dui[i]].k-=dq[i];
            }
            dq[i]=0;
        }
        for(int i=L;i<=R;i++) dui[i]=cc[i];
        solve(l,mid,L,hu1-1);
        solve(mid+1,r,hu2+1,R);
    }
    int main()
    {
        n=read();q=read();
        for(int i=1;i<=n;i++)
        {
            cin>>s;
            b[i].qi=zh.insert(s);
            reverse(s.begin(),s.end());
            b[i].ho=fa.insert(s);
        }
        zh.dfs(0);size=0;fa.dfs(0);
        for(int i=1;i<=n;i++)
        {
            b[i].qi=zh.dfn[b[i].qi];
            b[i].ho=fa.dfn[b[i].ho];
        }
        cj=fa.cnt+1;
        for(int i=1,x,y,z;i<=q;i++)
        {
            cin>>s>>ss>>z;
            dui[i]=i;
            reverse(ss.begin(),ss.end());
            x=zh.cha(s);
            y=fa.cha(ss);a[i].k=z;
            if(x==0||y==0) {ans[i]=-1;continue;}
            a[i].id=i;
            a[i].x1=zh.dfn[x];a[i].x2=zh.dfn[x]+zh.siz[x]-1;
            a[i].y1=fa.dfn[y];a[i].y2=fa.dfn[y]+fa.siz[y]-1;
        } 
        solve(1,n+1,1,q);
        for(int i=1;i<=q;i++) cout<<ans[i]<<"
    ";
        return 0;
    } 
  • 相关阅读:
    小组站立会议 星期四
    小组站立会议 星期三
    小组站立会议 星期二
    小组站立会议 星期一
    小组站立会议
    爱壁纸 站立会议(六)--Spring阶段总结会议
    爱壁纸 站立会议(五)
    爱壁纸 小组会议(四)
    爱壁纸-小组会议(三)
    MD5加密代码
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12130294.html
Copyright © 2011-2022 走看看