bzoj5253 [2018多省省队联测]制胡窜
后缀自动机挺好毒瘤的题。
我们考虑哪些切点是不合法的。肯定是所有的匹配串都被切了。
我们考虑第一个切口的位置。
当第一个切口在第一个出现位置前时,第二个切口必须切掉所有的串。
当第一个切口在$l_{i}$和$l_{i+1}$间的时候(此时必须保证切掉第一个串),第二个切口必须切掉$s_{i+1}$到$s_{cnt}$这些串
当第一个切口在$l_{cnt}$后时(此时依旧需要保证切掉第一个串),第二个切口随便放。
于是我们将询问离线,对于每个询问通过在parent树上倍增来找到所对应的节点。
对于后缀自动机上每个节点,通过平衡树启发式合并来维护他的right集合,之后我们只需要维护$\sum{(l_{i+1}-l_{i}) \cdot (r_{i+1}-l_{cnt})}$即可,然后拆开式子,就是$\sum{(r_{i+1}-r_{i}) \cdot r_{i+1}}$和$\sum{r_{i+1}-r_{i}}$。
因为每个询问的长度不同,又因为我们在上述第二三种情况都需要保证切掉第一个串,所以我们所需要提取的区间也不同,这个我们直接在平衡树上乱搞一下就可以了。
之后我们就可以愉快的AC掉这道好毒瘤题啦!
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#define N 100500
#define LL long long
using namespace std; int n,m;
char s[N];
struct data{
int l,r;
LL ans;
}d[];
vector <int> V[N<<]; #define siz(_) ((!(_))?(0):((_)->size))
#define tp pair<Treap *,Treap *>
struct Treap{
Treap *ch[];
int key,size,val,maxn,minn,val2,sum2;
LL val1,sum1;
//sum1=(r[i+1]-r[i])*r[i+1];
//sum2=(r[i+1]-r[i]);
Treap(int x){
val=maxn=minn=x;
key=rand();size=;
sum1=val1=sum2=val2=;
ch[]=ch[]=NULL;
}
void pushup(){
size=siz(ch[])+siz(ch[])+;
minn=maxn=val;
sum1=val1;sum2=val2;
if(ch[]){
minn=ch[]->minn;
sum1+=ch[]->sum1;
sum2+=ch[]->sum2;
}
if(ch[]){
maxn=ch[]->maxn;
sum1+=ch[]->sum1;
sum2+=ch[]->sum2;
}
}
}*root[N<<]; Treap *merge(Treap *a,Treap *b){
if(!a)return b;
if(!b)return a;
if(a->key<=b->key){
a->ch[]=merge(a->ch[],b);
a->pushup();return a;
}
else{
b->ch[]=merge(a,b->ch[]);
b->pushup();return b;
}
}
tp split(Treap *a,int k){
if(!a)return tp(NULL,NULL);
tp x;
if(siz(a->ch[])>=k){
x=split(a->ch[],k);
a->ch[]=x.second;
a->pushup();x.second=a;
}
else{
x=split(a->ch[],k-siz(a->ch[])-);
a->ch[]=x.first;
a->pushup();x.first=a;
}
return x;
}
int getrank(Treap *rt,int x){
int k=;
while(){
if(!rt)return k;
if(rt->val<x)k+=siz(rt->ch[])+,rt=rt->ch[];
else rt=rt->ch[];
}
}
void insert(Treap *&rt,int x){
int k=getrank(rt,x);
tp t=split(rt,k);
Treap *now=new Treap(x);
if(t.first){
tp w=split(t.first,k-);
now->val1=now->sum1=1ll*(x-w.second->val)*x;
now->val2=now->sum2=(x-w.second->val);
t.first=merge(w.first,w.second);
}
if(t.second){
tp w=split(t.second,);
w.first->val1=w.first->sum1=1ll*(w.first->val-x)*w.first->val;
w.first->val2=w.first->sum2=(w.first->val-x);
t.second=merge(w.first,w.second);
}
rt=merge(merge(t.first,now),t.second);
}
void dfs(Treap *o,Treap *&rt){
if(!o)return ;
dfs(o->ch[],rt);
insert(rt,o->val);
dfs(o->ch[],rt);
}
int find1(Treap *rt,int x){
if(rt==NULL)return ;
if(rt->val>=x)return find1(rt->ch[],x);
else{
if(!rt->ch[]||rt->ch[]->minn>=x)return rt->val;
return find1(rt->ch[],x);
}
}
int find2(Treap *rt,int x){
if(rt==NULL)return ;
if(rt->val<=x)return find2(rt->ch[],x);
else{
if(!rt->ch[]||rt->ch[]->maxn<=x)return rt->val;
return find2(rt->ch[],x);
}
}
void query(Treap *rt,int x,LL &s1,int &s2){
if(!rt)return ;
if(rt->val<=x){
if(rt->ch[])s1+=rt->ch[]->sum1,s2+=rt->ch[]->sum2;
s1+=rt->val1,s2+=rt->val2;
query(rt->ch[],x,s1,s2);
}
else query(rt->ch[],x,s1,s2);
}
LL query(int x,int l){
LL ans=;
int r1=root[x]->minn,r2=root[x]->maxn;
if(r2-l+<r1){
ans+=1ll*(r1-l)*(r1-(r2-l+));
ans+=1ll*(n-(r2-l)-+n-r1)*(r1-r2+l-)/;
}
int pos1=find1(root[x],r2-l+);
int pos2=find2(root[x],r1+l-);
if(!pos2)pos2=r2;
LL sum1=,sum2=;
int size1=,size2=;
query(root[x],pos1,sum1,size1);
query(root[x],pos2,sum2,size2);
if(pos2>pos1){
ans+=sum2-sum1;
ans-=1ll*(r2-l+)*(size2-size1);
if(pos2-l+>r1)ans-=1ll*((pos2-l+)-r1)*(pos2-(r2-l+));
}
return ans;
}
int last[N],tot,mx[N<<],ch[N<<][],par[N<<]; void extend(int x,int c){
int p=last[x-],np=++tot;
mx[np]=mx[p]+;
root[np]=NULL;
insert(root[np],x);
for(;p&&!ch[p][c];p=par[p])ch[p][c]=np;
if(!p) par[np]=;
else{
int q=ch[p][c];
if(mx[q]==mx[p]+)par[np]=q;
else{
int nq=++tot;
par[nq]=par[q];
memcpy(ch[nq],ch[q],sizeof ch[nq]);
mx[nq]=mx[p]+;
root[nq]=NULL;
par[q]=par[np]=nq;
for(;p&&ch[p][c]==q;p=par[p])ch[p][c]=nq;
}
}
last[x]=np;
}
int e=,head[N<<];
struct edge{
int v,next;
}ed[N<<];
void add(int u,int v){
ed[e].v=v;ed[e].next=head[u];
head[u]=e++;
}
int fa[N<<][];
void dfs(int x,int d){
for(int i=;(<<i)<=d;i++)
fa[x][i]=fa[fa[x][i-]][i-];
for(int i=head[x];i;i=ed[i].next){
fa[ed[i].v][]=x;
dfs(ed[i].v,d+);
}
}
int find(int x,int l){
for(int i=;~i;i--)
if(mx[fa[x][i]]>=l)x=fa[x][i];
return x;
}
void dfs(int x){
for(int i=head[x];i;i=ed[i].next){
dfs(ed[i].v);
if(siz(root[ed[i].v])>siz(root[x]))swap(root[x],root[ed[i].v]);
dfs(root[ed[i].v],root[x]);
}
for(int i=;i<V[x].size();i++){
int now=V[x][i];
d[now].ans=query(x,d[now].r-d[now].l+);
}
}
int main(){
scanf("%d%d",&n,&m);
scanf("%s",s+);
last[]=++tot;
for(int i=;i<=n;i++)extend(i,s[i]-'');
for(int i=;i<=tot;i++)add(par[i],i);
dfs(,);
for(int i=,x;i<=m;i++){
scanf("%d%d",&d[i].l,&d[i].r);
x=find(last[d[i].r],d[i].r-d[i].l+);
V[x].push_back(i);
}
dfs();
LL all=1ll*(n-)*(n-)/;
for(int i=;i<=m;i++){
d[i].ans=all-d[i].ans;
printf("%lld\n",d[i].ans);
}
return ;
}
bzoj5253 [2018多省省队联测]制胡窜的更多相关文章
- BZOJ_5249_Luogu_P4364_[2018多省省队联测]_IIIDX_九省联考2018_JLOI2018_线段树
BZOJ_5249_[2018多省省队联测]IIIDX_线段树 Description [题目背景] Osu听过没?那是Konano最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐 ...
- 5249: [2018多省省队联测]IIIDX
5249: [2018多省省队联测]IIIDX 链接 分析: 贪心. 将给定的权值从大到小排序,从第一个往后挨个赋值,考虑第i个位置可以赋值那些树.首先满足前面必须至少有siz[i]个权值没选,如果存 ...
- bzoj 5249 [2018多省省队联测] IIIDX
bzoj 5249 [2018多省省队联测] IIIDX Link Solution 首先想到贪心,直接按照从大到小的顺序在后序遍历上一个个填 但是这样会有大问题,就是有相同的数的时候,会使答案不优 ...
- Loj #2479. 「九省联考 2018」制胡窜
Loj #2479. 「九省联考 2018」制胡窜 题目描述 对于一个字符串 \(S\),我们定义 \(|S|\) 表示 \(S\) 的长度. 接着,我们定义 \(S_i\) 表示 \(S\) 中第 ...
- 【刷题】BZOJ 5248 [2018多省省队联测]一双木棋
Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子 ...
- bzoj 5248: [2018多省省队联测]一双木棋
Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子 ...
- bzoj 5251: [2018多省省队联测]劈配
Description 一年一度的综艺节目<中国新代码>又开始了. Zayid从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了. 题目描述 轻车熟路的Zayi ...
- bzoj5252 [2018多省省队联测]林克卡特树
斜率优化树形dp?? 我们先将问题转化成在树上选K+1条互不相交路径,使其权值和最大. 然后我们考虑60分的dp,直接维护每个点子树内选了几条路径,然后该点和0/1/2条路径相连 然后我们会发现最后的 ...
- bzoj5251 [2018多省省队联测]劈配
直接网络流模拟即可AC. 可持久化+暴力=90分, 可持久化+二分=30分, 暴力加边+二分=100分. 我也很无奈啊. Ivan便涨红了脸,额上的青筋条条绽出,争辩道,“memcpy也是可持久化…… ...
随机推荐
- 初步认识thymeleaf:简单表达式和标签(二)
1.th:each:循环,<tr th:each="user,userStat:${users}">,userStat是状态变量,有 index,count,size, ...
- char 与 String 相等比较
这是一个相当2 相当基础 相当没有意义的帖子:但今天因为这个问题引发了一个bug.小细节也很重要!!! char a='1'; // char b='2dsf'; //cha ...
- oracle to_date 函数
update pamsodt0p10 set cursysdate = to_date('2014-12-29 00:00:00','yyyy-mm-dd hh24:mi:ss') where cu ...
- ORACLE分页SQL语句(转载)
1.根据ROWID来分select * from t_xiaoxi where rowid in(select rid from (select rownum rn,rid from(select r ...
- javascript学习(二)javascript常见问题总结
在js使用过程中,经常会碰到一些问题,本人利用闲暇时间整理了一些常见问题的解决方法,贴出来和大家分享,有需要的朋友可以参考下 1.JS中方法和变量都是区分大小写的 2.单引号.双引号在JS中没有特殊 ...
- OpenStack初识
一.它可以用来做什么? 想认识一个事物,必须先弄明白它是什么,能干什么.首先说一下,openstack是一个搭建云平台的一个解决方案,说他不是个软件,但是我觉得说是一个软件,能够让初学者更容易接受和理 ...
- Python-Web框架之 - 利用SQLALchemy创建与数据库MySQL的连接, 详解用Flask时会遇到的一些大坑 !
经过这个小项目算是对Django与Flask这两个web框架有了新的认识 , Django本身的轮子非常齐全 , 套路也很固定 , 新手在接触Django框架时 , 不会陷入到处找轮子的大坑 ; 那么 ...
- 一个resin启动bug的解决
这个bug的问题后来被确认为Resin所在目录层有中文目录名.--------------------------------------------------------------------- ...
- bootstrap响应式设计简单实践。
首先需要熟悉Boostrap提供的响应式设施:http://getbootstrap.com/css/#responsive-utilities,BootStrap的响应式设施主要是利用媒体查询对元素 ...
- php添加日志文件
记录一下. 有时候写测试代码的时候,不习惯直接在屏幕上输出反馈,那么可以配置日志文件,把需要输出的内容追加到日志文件里面,就很方便. Php自带日志系统,可以参考网上的博客配置. 我要说的是,如果你的 ...