[Noi2016十连测第二场]幻想(后缀平衡树)

来源:互联网 发布:淘宝店铺卖气模名字 编辑:程序博客网 时间:2024/05/01 06:14

题意:给一个字符串,三种操作,末尾插入一个字符,弹出末尾的字符,查询区间内一个给定字符串出现了多少次。

卡常神题。。500万的数据规模什么鬼。。

假如没有区间限制,就是后缀平衡树的裸题。查询一个字符串s出现了多少次,就是在后缀平衡树上找出<s#的数量减去<s的数量,其中#是一个无穷大的字符,复杂度|s|logn。有区间限制的话写成平衡树套vector即可。。因为后缀平衡树用的是重量平衡树,所以是可以套东西的,重构的时候把vector归并了即可。注意归并之前vector需要resize!!!这个导致的RE使得我不明所以地调了一个多小时。。

由于替罪羊的删除不是很方便,这里可以用treap,删除一个节点的时候直接重构这个节点所在的子树。以前重构操作都是直接写在rotate里面的,用起来非常方便。这里为了常数问题,可以像替罪羊那样记录一个最高的需要重构的点重构即可。

考试的时候有人用分块过了的,就是将询问串分成比格和思茅。以后考试的时候如果不敢写正解的话可以试试这种分块来骗分。

#include<iostream>#include<algorithm>#include<cctype>#include<cstdio>#include<cstring>#include<vector>#define rep(i,a,b) for(int i=a;i<=b;++i)#define erp(i,a,b) for(int i=a;i>=b;--i)#define ALL(x) (x).begin(), (x).end()#define Exist(x,y) ((x) ? (x) : (y))#define pb push_back#define LL long longusing namespace std;const int MAXN = 500005;const LL INF = 1ll<<61;inline int ran() {static int a=5116213;return a=(a*1237+521)&0x7fffffff;}inline int get(char*s){int len = 0, c;do c=getchar(); while(!isalpha(c));do s[len++]=c, c=getchar(); while(isalpha(c));return s[len] = '\0', len;}inline int get(int&r){char c; r=0;do c=getchar(); while(c<'0'||c>'9');do r=r*10+c-'0',c=getchar(); while(c>='0'&&c<='9');}inline int cid(char x) { return x<='Z'?x-'A'+26:x-'a'; }inline char wrd(int x) { return x<26?x+'a':x-26+'A'; }char str[MAXN], s[MAXN*10];int Q, lens, ans;#define lch(x) (x->ch[0])#define rch(x) (x->ch[1])#define nodepos(x) ((x)-nds)#define siz(x) (x?x->sz:0)struct Node {Node *ch[2], *nxt;int fix, c;LL key;vector<int> vec;} nds[MAXN], *ncnt = nds, *rt;inline int calc(vector<int>&v, int l, int r){return upper_bound(ALL(v), r)-lower_bound(ALL(v), l);}inline void rotate(Node*&x, int d){Node*y = x->ch[!d];x->ch[!d] = y->ch[d];y->ch[d] = x;x = y;}inline int cmp(Node*x, Node*y){if (x->c^y->c) return x->c < y->c;return x->nxt->key < y->nxt->key;}inline void upvec(Node*x){x->vec.clear();if (lch(x)&&rch(x)){x->vec.resize(lch(x)->vec.size()+rch(x)->vec.size());merge(ALL(lch(x)->vec), ALL(rch(x)->vec), x->vec.begin());}else if (lch(x)&&!rch(x)) x->vec = lch(x)->vec;else if (rch(x)&&!lch(x)) x->vec = rch(x)->vec;int t = nodepos(x);x->vec.insert(upper_bound(ALL(x->vec), t), t);}void rebuild(Node*x, LL l, LL r){if (!x) return;LL mid = l+r>>1;x->key = l+r;rebuild(lch(x), l, mid);rebuild(rch(x), mid, r);upvec(x);}int rotflag;void ins(Node*&x, LL l, LL r){if (!x) { (x=ncnt)->key = l+r; return; }int d = cmp(x, ncnt);  //d=0表示插入节点比当前节点小LL mid = l+r>>1;if (!d) ins(lch(x), l, mid);else ins(rch(x), mid, r);if (x->ch[d]->fix > x->fix)rotate(x, !d);else{if (rotflag){if (!d) rebuild(lch(x), l, mid);else rebuild(rch(x), mid, r);rotflag = 0;}x->vec.pb(nodepos(ncnt));}if (x==rt&&rotflag)rebuild(x, l, r);}void del(Node*&x, LL l, LL r){LL mid = l+r>>1;if (x==ncnt){bool firstmeet = rotflag;rotflag = 0;if (!lch(x) || !rch(x)){x = Exist(lch(x), rch(x));if (!x) return;}else {if (lch(x)->fix>rch(x)->fix)rotate(x, 1), del(rch(x), mid, r);elserotate(x, 0), del(lch(x), l, mid);}if (firstmeet) rebuild(x, l, r);}else{x->vec.pop_back();if (ncnt->key < x->key) del(lch(x), l, mid);else del(rch(x), mid, r);}}inline void extend(int c){str[++lens] = c;(++ncnt)->c=c;ncnt->fix=ran(), ncnt->vec.clear();lch(ncnt)=rch(ncnt)=0x0, ncnt->nxt=ncnt-1;rotflag = 1, ins(rt, 1, INF);}inline void popchar(){rotflag = 1, del(rt, 1, INF);ncnt --, lens --;}int revlcp(Node*x, char*s, int len){int p = nodepos(x), l = 0;while (l<p&&l<len&&str[p-l]==s[len-l]) l++;return l;}int calcless(Node*x, char*s, int len, int l, int r) //查询x树中比s小的数量{if (l>r||!x) return 0;int sm = revlcp(x, s, len), d, p=nodepos(x); //d表示x是否比s小if (sm==len) d = p<len;else d = s[len-sm]>str[p-sm];int flag = p>=l&&p<=r&&d;if (!d) return calcless(lch(x), s, len, l, r);int lef = lch(x)?calc(lch(x)->vec, l, r):0;return lef + flag + calcless(rch(x), s, len, l, r);}int quary(int l, int r, char*s, int len){int L=l+len-1, R=r;int sum1 = calcless(rt, s, len, L, R);len++;erp(i, len, 2) s[i] = s[i-1];s[1] = 'z'+1;int sum2 = calcless(rt, s, len, L, R);return sum2 - sum1;}void decode(char*s, int len){rep(i, 1, len) s[i] = wrd((cid(s[i])+ans)%52);}int main(){int len = get(s+1);rep(i,1,len) extend(s[i]);get(Q);for (int op, l, r; Q--; ){get(op);if (op==1){get(s+1);decode(s,1);extend(s[1]);}else if (op==2) popchar();else {get(l), get(r);l^=ans, r^=ans;len = get(s+1);decode(s,len);ans = quary(l, r, s, len);printf("%d\n", ans);}}return 0;}

0 0
原创粉丝点击