码迷,mamicode.com
首页 > 其他好文 > 详细

Fence(codeforces 232D)

时间:2017-03-21 22:59:40      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:nbsp   tmp   长度   数组   query   主席树   bsp   定义   namespace   

题意:

对于给定的a[1..n],定义区间[s,t]和[x,y]"匹配"当且仅当下列条件同时满足:
1. t-s=y-x,即长度相同。
3. t<x或s>y,即两区间没有交。
2. 对任0<=i<=t-s,有a[s]+a[x]=a[s+i]+a[x+i]。
现给出a[1..n]和Q个询问(x,y),求与[x,y]匹配的区间的个数。

/*
    写了n个小时,还没有调出来,Orz...
    代码量倒是不大,但是细节巨多,已经弃疗了。。。
     
    先差分一下, 然后题目就变成了,也就是这段区间取相反数之后可以与原区间匹配。
    设当前询问为(x,y),把整个串取相反数,再复制到后面,用后缀数组向上向下二分出可行区间。 
    然后要求不可重叠,就是求rank在(l,r)中有多少串的位置在一个区间内,用主席树搞一搞。
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 200010
using namespace std;
int id[N],a[N],b[N],s[N],t1[N],t2[N],c[N],sa[N],rank[N],height[N],n;
int lg2[N],st[N][20],sum[N*11],son[N*11][2],root[N],cnt;
struct node{
    int x,num;
    bool operator<(const node&s1)const{
        if(x==s1.x) return num<s1.num;
        return x<s1.x;
    }
}r[N];
bool cmp(int *y,int a,int b,int k){
    int a1=y[a],b1=y[b];
    int a2=a+k<=n?y[a+k]:-1;
    int b2=b+k<=n?y[b+k]:-1;
    return a1==b1&&a2==b2;
}
void DA(){
    int *x=t1,*y=t2,m=1;
    for(int i=1;i<=n;i++) r[i]=(node){s[i],i};
    sort(r+1,r+n+1);
    for(int i=1;i<=n;i++) sa[i]=r[i].num;
    x[sa[1]]=1;
    for(int i=2;i<=n;i++) x[sa[i]]=r[i].x==r[i-1].x?m:++m;
    for(int k=1,p=0;k<=n;k*=2,m=p,p=0){
        for(int i=n-k+1;i<=n;i++) y[++p]=i;
        for(int i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
        for(int i=1;i<=m;i++) c[i]=0;
        for(int i=1;i<=n;i++) c[x[y[i]]]++;
        for(int i=2;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
        swap(x,y);p=1;x[sa[1]]=1;
        for(int i=2;i<=n;i++)
            if(cmp(y,sa[i-1],sa[i],k)) x[sa[i]]=p;
            else x[sa[i]]=++p;
        if(p>=n) break;
    }
}
void geth(){
    for(int i=1;i<=n;i++) rank[sa[i]]=i;
    for(int i=1,j=0;i<=n;i++){
        if(rank[i]==1) continue;
        while(s[i+j]==s[sa[rank[i]-1]+j]) j++;
        height[rank[i]]=j;
        if(j) j--;
    }
    for(int i=2;i<=n;i++) lg2[i]=lg2[i>>1]+1;
    for(int i=1;i<=n;i++) st[i][0]=height[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
void insert(int &k,int last,int l,int r,int pos){
    k=++cnt;
    son[k][0]=son[last][0];
    son[k][1]=son[last][1];
    sum[k]=sum[last]+1;
    if(l==r) return;
    int mid=l+r>>1;
    if(pos<=mid) insert(son[k][0],son[last][0],l,mid,pos);
    else insert(son[k][1],son[last][1],mid+1,r,pos);
}
int query(int k,int l,int r,int x,int y){
    if(l>=x&&r<=y) return sum[k];
    int mid=l+r>>1,tot=0;
    if(x<=mid) tot+=query(son[k][0],l,mid,x,y);
    if(y>mid) tot+=query(son[k][1],mid+1,r,x,y);
    return tot;
}
int querymn(int x,int y){
    int k=lg2[y-x+1];
    return min(st[x][k],st[y-(1<<k)+1][k]);
}
int work(int x,int y){
    int pos=rank[x],l=0,r=pos,tmp1=pos,tmp2=pos;
    while(l<r-1){
        int mid=l+r>>1;
        if(querymn(mid+1,pos)>=y-x+1) r=mid,tmp1=mid;
        else l=mid;
    }
    l=pos,r=n+1;
    while(l<r-1){
        int mid=l+r>>1;
        if(querymn(pos+1,mid)>=y-x+1) l=mid,tmp2=mid;
        else r=mid;
    }
    int ans1=query(root[tmp2],1,n+1,x+n/2+1,y+n/2+2)-query(root[tmp1-1],1,n+1,x+n/2+1,y+n/2+2);
    int ans2=query(root[tmp2],1,n,1,n/2)-query(root[tmp1-1],1,n,1,n/2);
    return tmp2-tmp1+1-ans1-ans2;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<n;i++) s[i]=a[i+1]-a[i],s[i+n]=-s[i];s[n]=-1e9;
    n=n*2-1;DA();geth();
    for(int i=1;i<=n;i++)
        insert(root[i],root[i-1],1,n,sa[i]);
    int Q;scanf("%d",&Q);
    while(Q--){
        int x,y;scanf("%d%d",&x,&y);
        if(x==y){
            printf("%d\n",n/2);
            continue;
        }
        printf("%d\n",work(x,y-1));
    }
    return 0;
}

 

Fence(codeforces 232D)

标签:nbsp   tmp   长度   数组   query   主席树   bsp   定义   namespace   

原文地址:http://www.cnblogs.com/harden/p/6597046.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!