HDU 6096 树套树

Posted siriusren

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6096 树套树相关的知识,希望对你有一定的参考价值。

思路:

网上的题解有AC自动机的,有trie树的,还有(乱搞?)的

 

首先把输入的那n个串按照字典序排序,

把n个串翻转以后再按照字典序排序

这样我们发现, 查的前缀在字典序排序后是一段区间,

查的后缀翻转一下在翻转后的字典序排序以后也是一段区间

这样如果不考虑重叠的问题,就是一个简单的二维数点问题,一维排序,一维线段树即可解决

 

如果有重叠的问题,我们需要搞出来每个字符串的长度,使给出的前缀长+后缀长>=原字符串长度

此时题目变成了三维偏序,排序后树套树即可。

//By SiriusRen
#include <bits/stdc++.h>
using namespace std;
const int N=500050;
int cases,n,q,root[N<<3],cnt,tree[N*150],lson[N*150],rson[N*150];
struct Node{string str;int id,len;}X[N],Y[N],tmp;
bool operator<(Node a,Node b){return a.str<b.str;}
struct Pnt{int x,y,z;}p[N];
struct Ask{int xl,xr,yl,yr,z,id,ans;}ask[N];
bool cmp1(Pnt a,Pnt b){return a.z>b.z;}
bool cmp2(Ask a,Ask b){return a.z>b.z;}
bool cmp3(Ask a,Ask b){return a.id<b.id;}
void Insert(int l,int r,int &pos,int wei){
    if(!pos)pos=++cnt;tree[pos]++;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(mid>=wei)Insert(l,mid,lson[pos],wei);
    else Insert(mid+1,r,rson[pos],wei);
}
void insert(int l,int r,int pos,int num,int wei){
    Insert(1,n,root[pos],wei);
    if(l==r)return;
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<num)insert(mid+1,r,rson,num,wei);
    else insert(l,mid,lson,num,wei);
}
int Query(int l,int r,int pos,int L,int R){
    if(l>=L&&r<=R)return tree[pos];
    int mid=(l+r)>>1;
    if(mid<L)return Query(mid+1,r,rson[pos],L,R);
    else if(mid>=R)return Query(l,mid,lson[pos],L,R);
    else return Query(l,mid,lson[pos],L,R)+Query(mid+1,r,rson[pos],L,R);
}
int query(int l,int r,int pos,int xl,int xr,int yl,int yr){
    if(l>=xl&&r<=xr)return Query(1,n,root[pos],yl,yr);
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<xl)return query(mid+1,r,rson,xl,xr,yl,yr);
    else if(mid>=xr)return query(l,mid,lson,xl,xr,yl,yr);
    else return query(l,mid,lson,xl,xr,yl,yr)+query(mid+1,r,rson,xl,xr,yl,yr);
}
int main(){
    ios::sync_with_stdio(false);
    cin>>cases;
    while(cases--){
        memset(tree,0,sizeof(int)*(cnt+5));
        memset(lson,0,sizeof(int)*(cnt+5));
        memset(rson,0,sizeof(int)*(cnt+5));
        memset(root,0,sizeof(root));cnt=0;
        cin>>n>>q;
        for(int i=1;i<=n;i++)cin>>X[i].str;
        sort(X+1,X+1+n);
        for(int i=1;i<=n;i++)X[i].id=i,X[i].len=X[i].str.length();
        for(int i=1;i<=n;i++)Y[i]=X[i];
        for(int i=1;i<=n;i++)reverse(Y[i].str.begin(),Y[i].str.end());
        sort(Y+1,Y+1+n);
        for(int i=1;i<=n;i++)p[i].x=Y[i].id,p[i].y=i,p[i].z=Y[i].len;
        for(int i=1;i<=q;i++){
            string pre,suf;cin>>pre>>suf;
            ask[i].id=i;tmp.str=pre;
            ask[i].xl=lower_bound(X+1,X+1+n,tmp)-X;
            tmp.str=pre,tmp.str.push_back(z+1);
            ask[i].xr=lower_bound(X+1,X+1+n,tmp)-X-1;
            tmp.str=suf,reverse(tmp.str.begin(),tmp.str.end());
            ask[i].yl=lower_bound(Y+1,Y+1+n,tmp)-Y;
            tmp.str.push_back(z+1);
            ask[i].yr=lower_bound(Y+1,Y+1+n,tmp)-Y-1;
            ask[i].z=pre.size()+suf.size();
        }
        sort(p+1,p+1+n,cmp1);sort(ask+1,ask+1+q,cmp2);
        int tt=1;
        for(int i=1;i<=q;i++){
            while(p[tt].z>=ask[i].z&&tt<=n)insert(1,n,1,p[tt].x,p[tt].y),tt++;
            if(ask[i].xl>ask[i].xr||ask[i].yl>ask[i].yr){ask[i].ans=0;continue;}
            ask[i].ans=query(1,n,1,ask[i].xl,ask[i].xr,ask[i].yl,ask[i].yr);
        }sort(ask+1,ask+1+q,cmp3);
        for(int i=1;i<=q;i++)cout<<ask[i].ans<<endl;
    }
}

 

以上是关于HDU 6096 树套树的主要内容,如果未能解决你的问题,请参考以下文章

#树套树,二维线段树#HDU 4819 Mosaic

[HDOJ1823] Luck and Love(线段树,树套树)

树套树乱讲的代码

「luogu3380」模板二逼平衡树(树套树)

「模板」 树套树

树套树三题 题解