BZOJ 3439: Kpm的MC密码 (trie+dfs序主席树)

10 篇文章 0 订阅
5 篇文章 0 订阅

题意

分析

把串倒过来插进 t r i e trie trie上, 那么一个串的 k p m kpm kpm串就是这个串在 t r i e trie trie上对应的结点的子树下面的所有字符串.
那么像 BZOJ 3551/3545: [ONTAK2010]Peaks加强版 d f s dfs dfs序+主席树就可以 O ( n l o g n ) O(nlogn) O(nlogn)解决查找子树第 k k k小问题
但是与 BZOJ 3551/3545: [ONTAK2010]Peaks加强版 不同的是,这道题可能出现相同的串,于是在 t r i e trie trie树上用链表把编号链起来就行了.


s b sb sb了,没想到超水的做法…geng4512的博客

CODE

#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &res) {
    char ch; int flg = 1; for(;!isdigit(ch=getc());)if(ch=='-')flg=-flg;
    for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0'); res*=flg;
}
const int MAXN = 100005;
const int MAXL = 300005;
const int MAXC = 26;

int n, num[MAXN], trie_tot, in[MAXL], out[MAXL], tmr, seq[MAXN]; char s[MAXL];

struct seg { //主席树

	seg *ls, *rs;
	int sum;

	inline void* operator new (size_t, seg *Ls, seg *Rs, int _) {
		static seg *mempool, *C;
		if(C == mempool) mempool = (C = new seg[1<<15]) + (1<<15);
		C->ls = Ls;
		C->rs = Rs;
		C->sum = _;
		return C++;
	}

}*rt[MAXL];

struct O { //链表

	O *nxt;
	int v;

	inline void* operator new(size_t, O *Nxt, int _) {
		static O *mempool, *C;
		if(C == mempool) mempool = (C = new O[1<<15]) + (1<<15);
		C->nxt = Nxt;
		C->v = _;
		return C++;
	}

}*head[MAXL];

struct trie {

	trie *ch[MAXC];
	int v;

	inline void* operator new(size_t) {
		static trie *mempool, *C;
		if(C == mempool) mempool = (C = new trie[1<<15]) + (1<<15);
		C->v = ++trie_tot;
		return C++;
	}

}*root;

inline void add(int x, int v) {
	head[x] = new(head[x], v) O;
}
inline void insert(int id, int i) {
	trie *r = root;
	while(~i) {
		if(!r->ch[s[i]-'a'])
			r->ch[s[i]-'a'] = new trie;
		r = r->ch[s[i]-'a'];
		i--;
	}
	add(num[id] = r->v, id); //用链表链起来
}

void dfs(trie *x) {
	in[x->v] = tmr + 1;
	for(O *i = head[x->v]; i; i = i->nxt)
		seq[++tmr] = i->v;
	for(int i = 0; i < MAXC; ++i)
		if(x->ch[i]) dfs(x->ch[i]);
	out[x->v] = tmr;
}

seg* insert(seg *p, int l, int r, int x) {
	if(l == r) return new(0x0, 0x0, p->sum+1) seg;
	int mid = (l + r) >> 1;
	if(x <= mid) return new(insert(p->ls, l, mid, x), p->rs, p->sum+1) seg;
	else return new(p->ls, insert(p->rs, mid+1, r, x), p->sum+1) seg;
}

inline int query(int i, int k) {
	seg *x = rt[in[i]-1], *y = rt[out[i]];
	if(y->sum - x->sum < k) return -1;
	int l = 1, r = n, mid;
	while(l < r) {
		mid = (l + r) >> 1;
		if(y->ls->sum - x->ls->sum >= k)
			x = x->ls, y = y->ls, r = mid;
		else k -= y->ls->sum - x->ls->sum, x = x->rs, y = y->rs, l = mid+1;
	}
	return l;
}

int main () {
	read(n); root = new trie;
	for(int i = 1; i <= n; ++i) {
		while(!isalpha(s[0]=getc())); int len = 0;
		while(isalpha(s[++len]=getc()));
		insert(i, len-1);
	}
	dfs(root);
	rt[0] = new(0x0, 0x0, 0) seg; //初始化空树
	rt[0]->ls = rt[0]->rs = rt[0];
	for(int i = 1; i <= n; ++i)
		rt[i] = insert(rt[i-1], 1, n, seq[i]);
	
	for(int i = 1, x; i <= n; ++i)
		read(x), printf("%d\n", query(num[i], x));
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值