zoukankan      html  css  js  c++  java
  • K-th occurrence HDU

    大意: 给定串$s$, $q$个询问$(l,r,k)$, 求子串$s[l,r]$的第$k$次出现位置.

    本来是个简单签到题, 可惜比赛的时候还没学$SA$...... 好亏啊

    相同的子串在$SA$中是一定是连续的一段$[L,R]$

    满足对于$L<ile R$都有$h_ige r-l+1$

    可以先用线段树二分出$L,R$, 然后主席树查询第$k$大即可 

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    using namespace std;
    const int N = 1e5+10;
    int n, q, tot, a[N], T[N];
    struct {int l,r,v;} tr[N*40];
    char s[N];
    int c[N],rk[N],h[N],sa[N],mi[N<<2];
    
    void build(int *a, int n, int m) {
    	a[n+1] = 0;
        int i,*x=rk,*y=h;
        for(i=1;i<=m;i++) c[i]=0;
        for(i=1;i<=n;i++) c[x[i]=a[i]]++;
        for(i=1;i<=m;i++) c[i]+=c[i-1];
        for(i=n;i;i--) sa[c[x[i]]--]=i;
        for(int k=1,p;k<=n;k<<=1) {
            p=0;
            for(i=n-k+1;i<=n;i++) y[++p]=i;
            for(i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
            for(i=1;i<=m;i++) c[i]=0;
            for(i=1;i<=n;i++) c[x[y[i]]]++;
            for(i=1;i<=m;i++) c[i]+=c[i-1];
            for(i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
            swap(x,y); x[sa[1]]=1; p=1;
            for(i=2;i<=n;i++)
                x[sa[i]]=(y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])?p:++p;
            if(p==n) break; m=p;
        }
        for(i=1;i<=n;i++) rk[sa[i]]=i;
        for(int i=1,j,k=0;i<=n;i++){
            if(k) k--;
            j=sa[rk[i]-1];
            while (a[i+k]==a[j+k]) k++;
            h[rk[i]] = k;
        }
    }
    //求最小的位置p, 使得[p,x]的最小值>=v
    int find1(int o, int l, int r, int x, int v) {
    	if (r<=x) {
    		if (l==r) return mi[o]>=v?l:-1;
    		if (mi[rc]<v) return find1(rs,x,v);
    		int t = find1(ls,x,v);
    		return t==-1?mid+1:t;
    	}
    	if (mid>=x) return find1(ls,x,v);
    	int R = find1(rs,x,v);
    	if (R==-1||R>mid+1) return R;
    	int L = find1(ls,x,v);
    	return L==-1?R:L;
    }
    //求找最大的位置p, 使得[x,p]的最小值>=v
    int find2(int o, int l, int r, int x, int v) {
    	if (x<=l) {
    		if (l==r) return mi[o]>=v?l:-1;
    		if (mi[lc]<v) return find2(ls,x,v);
    		int t = find2(rs,x,v);
    		return t==-1?mid:t;
    	}
    	if (mid<x) return find2(rs,x,v);
    	int L = find2(ls,x,v);
    	if (L==-1||L<mid) return L;
    	int R = find2(rs,x,v);
    	return R==-1?L:R;
    }
    int query(int u, int v, int l, int r, int k) {
    	if (l==r) return l;
    	int s = tr[tr[v].l].v-tr[tr[u].l].v;
    	if (s>=k) return query(tr[u].l,tr[v].l,l,mid,k);
    	return query(tr[u].r,tr[v].r,mid+1,r,k-s);
    }
    void add(int &o, int l, int r, int x) {
    	tr[++tot]=tr[o],o=tot,++tr[o].v;
    	if (l!=r) mid>=x?add(tr[o].l,l,mid,x):add(tr[o].r,mid+1,r,x);
    }
    int query(int p, int len, int k) {
    	int l = p>1?find1(1,2,n,p,len)-1:1;
    	int r = p<n?find2(1,2,n,p+1,len):n;
    	if (l<0) l = p;
    	if (r<0) r = p;
    	if (r-l+1>=k) return query(T[l-1],T[r],1,n,k);
    	return -1;
    }
    void build2(int o, int l, int r) {
    	if (l==r) return mi[o]=h[l],void();
    	build2(ls),build2(rs);
    	mi[o]=min(mi[lc],mi[rc]);
    }
    void brute_force() {
    	while (q--) {
    		int l, r, k;
    		scanf("%d%d%d",&l,&r,&k);
    		string g(s+l,s+r+1);
    		int pos = -1, cnt = 0;
    		REP(i,1,n) if (string(s+i,s+i+r-l+1)==g) { 
    			if (++cnt==k) {
    				pos = i; break;
    			}
    		}
    		printf("%d
    ", pos);
    	}
    }
    int main() {
    	int t;
    	scanf("%d", &t);
    	while (t--) {
    		scanf("%d%d%s", &n, &q, s+1);
    		if (n<=10) {brute_force();continue;}
    		REP(i,1,n) a[i]=s[i]-'a'+1;
    		build(a,n,26);
    		build2(1,2,n);
    		REP(i,1,n) {
    			T[i] = T[i-1];
    			add(T[i],1,n,sa[i]);
    		}
    		while (q--) {
    			int l, r, k;
    			scanf("%d%d%d", &l, &r, &k);
    			int len = r-l+1;
    			printf("%d
    ", query(rk[l],r-l+1,k));
    		}
    		REP(i,0,n) T[i]=0;
    		while (tot) tr[tot].l=tr[tot].r=tr[tot].v=0,--tot;
    	}
    }
    
  • 相关阅读:
    【PyQt5-Qt Designer】对话框系列
    【PyQt5-Qt Designer】界面布局
    【PyQt5-Qt Designer】PyQt5+eric6 安装和配置
    【PyQt5-Qt Designer】QMessageBox 弹出框总结
    【PyQt5-Qt Designer】鼠标+键盘事件
    【PyQt5-Qt Designer】猜数字(小项目)
    【PyQt5-Qt Designer】浅谈关闭窗口
    【PyQt5-Qt Designer】窗口操作
    【python基础】利用pandas处理Excel数据
    【python基础】os.path模块常用方法详解
  • 原文地址:https://www.cnblogs.com/uid001/p/11405505.html
Copyright © 2011-2022 走看看