[BZOJ5351]Query on a sequence

题目大意:

给定一个长度为\(n(n\le10^5)\)的数列\(P\),满足\(|P_i|\le10^9\),求满足下列约束的不同的四元组\((a,b,c,d)\)的个数:

  1. \(1\le a\le b<c\le d\le n\);
  2. \(b-a=d-c\);
  3. \(c-b-1=m\),\(m(m>0)\)为给定的数;
  4. \(p_{a+i}=P_{c+i}\)对于所有\(i(0\le i\le b-a)\)均成立。

思路:

对于\(a\)和\(c\),若\(c-a>m\),且对于后缀\(S_a\)和\(S_c\),有\(\operatorname{lcp}(S_a,S_c)\ge c-a-m\),则我们可以求出合法的\(b\)和\(d\)的区间。

首先对于数列建立后缀数组。从大到小枚举\(lcp[i]\),合并其对应的两个后缀\(a\)和\(c\),因为若下一条枚举到的\(lcp[j]\)如果是关于\(c\)的,则由于\(lcp[i]\ge lcp[i]\),它一样可以适用于\(a\)。对于每个连通块用线段树维护数列每个区间内的数开头的每个后缀是否出现。统计时枚举连通块内每一个后缀,枚举它是\(a\)还是\(c\),在线段树上查找区间和即可。

源代码:

#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
inline int getint() {
register char ch;
register bool neg=false;
while(!isdigit(ch=getchar())) neg|=ch=='-';
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=1e5+1;
int n,m,k,s[N],sa[N],rank[N],tmp[N];
std::pair<int,int> lcp[N];
inline bool cmp(const int &i,const int &j) {
if(rank[i]!=rank[j]) return rank[i]<rank[j];
const int ri=i+k<=n?rank[i+k]:-1;
const int rj=j+k<=n?rank[j+k]:-1;
return ri<rj;
}
inline void suffix_sort() {
for(register int i=0;i<=n;i++) {
sa[i]=i;
rank[i]=s[i];
}
for(k=1;k<=n;k<<=1) {
std::sort(&sa[0],&sa[n+1],cmp);
tmp[sa[0]]=0;
for(register int i=1;i<=n;i++) {
tmp[sa[i]]=tmp[sa[i-1]]+!!cmp(sa[i-1],sa[i]);
}
std::copy(&tmp[0],&tmp[n]+1,rank);
}
};
inline void init_lcp() {
for(register int i=0,h=0;i<n;i++) {
if(h>0) h--;
const int &j=sa[rank[i]-1];
while(i+h<n&&j+h<n&&s[i+h]==s[j+h]) h++;
lcp[rank[i]-1]=std::make_pair(-h,rank[i]);
}
}
const int SIZE=N*20;
class SegmentTree {
private:
struct Node {
int val,left,right;
};
Node node[SIZE];
int sz,new_node() {
return ++sz;
}
public:
int root[N];
void insert(int &p,const int &b,const int &e,const int &x) {
node[p=new_node()].val++;
if(b==e) return;
const int mid=(b+e)>>1;
if(x<=mid) insert(node[p].left,b,mid,x);
if(x>mid) insert(node[p].right,mid+1,e,x);
}
int query(const int &p,const int &b,const int &e,const int &l,const int &r) const {
if(r<l) return 0;
if(b==l&&e==r) return node[p].val;
const int mid=(b+e)>>1;
int ret=0;
if(l<=mid) ret+=query(node[p].left,b,mid,l,std::min(mid,r));
if(r>mid) ret+=query(node[p].right,mid+1,e,std::max(mid+1,l),r);
return ret;
}
int merge(const int &x,const int &y) {
if(!x||!y) return x|y;
node[y].val+=node[x].val;
node[y].left=merge(node[x].left,node[y].left);
node[y].right=merge(node[x].right,node[y].right);
return y;
}
};
SegmentTree t;
struct DisjointSet {
int anc[N],min[N],size[N];
int find(const int &x) {
return x==anc[x]?x:anc[x]=find(anc[x]);
}
void reset() {
for(register int i=1;i<=n;i++) {
size[i]=1;
anc[i]=min[i]=i;
}
}
void merge(const int &x,const int &y) {
anc[x]=y;
min[y]=std::min(min[x],min[y]);
size[y]+=size[x];
}
};
DisjointSet djs;
int lim,ans;
inline void merge(int x,int y) {
x=djs.find(x),y=djs.find(y);
if(djs.size[x]>djs.size[y]) std::swap(x,y);
for(register int i=djs.min[x];i<djs.min[x]+djs.size[x];i++) {
ans+=t.query(t.root[y],1,n,std::max(sa[i]+1+m+1,1),std::min(sa[i]+1+lim,n));
ans+=t.query(t.root[y],1,n,std::max(sa[i]+1-lim,1),std::min(sa[i]+1-m-1,n));
}
djs.merge(x,y);
t.merge(t.root[x],t.root[y]);
}
int main() {
n=getint(),m=getint();
for(register int i=0;i<n;i++) s[i]=getint();
s[n]=INT_MIN;
suffix_sort();
init_lcp();
std::sort(&lcp[0],&lcp[n]);
for(register int i=1;i<=n;i++) {
t.insert(t.root[i],1,n,sa[i]+1);
}
djs.reset();
for(register int i=0;i<n;i++) {
lim=-lcp[i].first+m;
merge(lcp[i].second,lcp[i].second-1);
}
printf("%d\n",ans);
return 0;
}

[BZOJ5351]Query on a sequence的更多相关文章

  1. C#/.NET Little Wonders: Use Cast() and OfType() to Change Sequence Type(zz)

    Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, ...

  2. HDU 4441 Queue Sequence(优先队列+Treap树)(2012 Asia Tianjin Regional Contest)

    Problem Description There's a queue obeying the first in first out rule. Each time you can either pu ...

  3. LinqToDB 源码分析——生成与执行SQL语句

    生成SQL语句的功能可以算是LinqToDB框架的最后一步.从上一章中我们可以知道处理完表达式树之后,相关生成SQL信息会被保存在一个叫SelectQuery类的实例.有了这个实例我们就可以生成对应的 ...

  4. LinqToDB 源码分析——处理表达式树

    处理表达式树可以说是所有要实现Linq To SQL的重点,同时他也是难点.笔者看完作者在LinqToDB框架里面对于这一部分的设计之后,心里有一点不知所然.由于很多代码没有文字注解.所以笔者只能接合 ...

  5. Elven Postman(BST )

    Elven Postman Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

  6. of

    “查询序列的一个元素” 1. an element of the query sequence (T) 2. an query sequence element (T) "查询序列或者候选序 ...

  7. hdu 5444 Elven Postman 二叉树

    Time Limit: 1500/1000 MS (Java/Others)   Memory Limit: 131072/131072 K (Java/Others) Problem Descrip ...

  8. Regional Changchun Online--Elven Postman(裸排序二叉树)

    Elven Postman Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Tot ...

  9. hdu 5444 Elven Postman

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5444 Elven Postman Description Elves are very peculia ...

随机推荐

  1. Ribbon的主要组件与工作流程

    一:Ribbon是什么? Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起.Ribbon客户端组件提供一系列完善的配置项如连接 ...

  2. 使用Sysmon分析宏病毒(Macros Downloader)

    样本为一个Word文件,Virustotal地址: https://www.virustotal.com/#/file/f8aede78ad92bd28f5f699b677d7d5fd362c8be8 ...

  3. ubuntu tomcat的安装与配置

    一.下载jdk 大概是tomat大部分是由java写的, 所以一开始安装tomcat必须得配置好jdk http://www.oracle.com/technetwork/java/javase/do ...

  4. Makefile parameters pass 參數傳遞

    command $make ARCH=7777777777777777777777777777777 Makefile content $(warning $(ARCH)) output Makefi ...

  5. 工具===代替cmd的conemu设置

    conemu设置 Win+Alt+P进入设置界面,字体设置: 隐藏右上角菜单和窗口标题. (Ctrl + ~ 隐藏/显示terminal) 设置背景图片 避免误操作,关闭/新建确认 设置win+w默认 ...

  6. Python Matplotlib图表汉字显示成框框的解决办法

    http://blog.sina.com.cn/s/blog_662dcb820102vu3d.html http://blog.csdn.net/fyuanfena/article/details/ ...

  7. Linux(Unix)密码策略问题导致root密码不能修改

    Linux(Unix)密码策略问题导致root密码不能修改 发布时间:  2016-01-19 浏览次数:  1034 下载次数:  5 用户修改了密码配置文件,导致root账户修改密码时报如下错误: ...

  8. Multiply Strings——面试题

    Given two numbers represented as strings, return multiplication of the numbers as a string. Note: Th ...

  9. 解决错误:此用户名包含无效字符,请输入有效的用户名。wordpress不能注册中文用户名的问题

    wordpress在默认情况下不支持中文用户名,就是在后台添加用户的时候,如果用户名包含中文,则显示”错误:此用户名包含无效字符,请输入有效的用户名.”如何解决这个问题呢? 不用插件的话就需要修改一个 ...

  10. YumRepo Error: All mirror URLs are not using

    yum 安装软件出错,最后发现是网络被拦截导致.