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

CF1286E Fedya the Potter Strikes Back

时间:2020-10-06 21:16:44      阅读:41      评论:0      收藏:0      [点我收藏+]

标签:getc   read   map   fine   return   颜色不同   scanf   产生   main   

只需考虑每次加入后答案的增量,即增加的子串的答案。

发现有贡献的子串为 \(\text{border}\),那么每次就只需维护 \(\text{border}\) 集合的变化。若子串 \([1,pos]\) 为子串 \([1,i]\) 的一个 \(\text{border}\),则 \(s_{pos+1}=s_{i+1}\) 时,子串 \([1,pos+1]\) 就仍为子串 \([1,i+1]\) 的一个合法的 \(\text{border}\)

考虑加入位置 \(i\) 后如何处理。若产生了新的 \(\text{border}\),就直接加入,即 \(s_1=s_i\)。考虑如何删去不合法的 \(\text{border}\)。设位置 \(i\) 的颜色为 \(s_i+1\),加入后不合法的 \(\text{border}\) 为位置 \(i\)\(\text{border}\) 结尾位置的颜色不一样。那么用 \(kmp\) 的失配指针构建一棵树,在每个节点上对每一种颜色都维护出最近的该颜色的祖先,每次就在树上删去和当前加入的颜色不同的 \(\text{border}\),删除时需要查询区间最小值,用线段树维护即可。因为每个 \(\text{border}\) 只会被删除一次且每次最多加入一个 \(\text{border}\),因此复杂度有保证。维护 \(\text{border}\) 的权值时要做到对所有的权值和 \(w_i\)\(\min\),这里用 \(map\) 维护每个权值的出现次数,修改就暴力修改即可。因为每个加入的权值最多被暴力取 \(\min\) 一次,因此复杂度有保证。

时间复杂度为 \(O(n \log n)\)

#include<bits/stdc++.h>
#define maxn 600010
#define maxm 2400010
#define inf 2000000000
#define mod 1000000000000000000
#define ls (cur<<1)
#define rs (cur<<1|1)
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c==‘-‘)flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,root=1,pos;
ll val;
int s[maxn],w[maxn],nxt[maxn],col[maxn],fa[maxn][28],st[maxn],mn[maxm];
char c[5];
map<ll,int> mp;
pair<ll,ll> ans;
pair<ll,ll> operator +(const pair<ll,ll> &x,const ll &y)
{
    return make_pair((x.first+y)%mod,x.second+(x.first+y)/mod);
}
ll operator %(const pair<ll,ll> &x,const ll &p)
{
    return (x.first%p+(x.second%p)*(mod%p)%p)%p;
}
void write(pair<ll,ll> x)
{
    if(x.second) printf("%lld%018lld\n",x.second,x.first);
    else printf("%lld\n",x.first);
}
void modify(int l,int r,int pos,int v,int cur)
{
    if(l==r)
    {
        mn[cur]=v;
        return;
    }
    if(pos<=mid) modify(l,mid,pos,v,ls);
    else modify(mid+1,r,pos,v,rs);
    mn[cur]=min(mn[ls],mn[rs]);
}
int query(int L,int R,int l,int r,int cur)
{
    if(L<=l&&R>=r) return mn[cur];
    int v=inf;
    if(L<=mid) v=min(v,query(L,R,l,mid,ls));
    if(R>mid) v=min(v,query(L,R,mid+1,r,rs));
    return v;
}
void add(ll x,int v)
{
    mp[x]+=v,val+=x*v;
}
int update(int x)
{
    int cnt=0,top=0;
    for(map<ll,int>::iterator it=mp.upper_bound(x);it!=mp.end();++it)
        st[++top]=it->first,cnt+=it->second,val-=it->first*it->second;
    while(top) mp.erase(st[top--]);
    return cnt;
}
int main()
{
    read(n),scanf("%s",c),s[1]=c[0]-‘a‘,read(w[1]);
    modify(1,n,1,w[1],root),ans=ans+w[1],write(ans);
    for(int i=2;i<=n;++i)
    {
        scanf("%s",c),read(w[i]);
        s[i]=(c[0]-‘a‘+ans%26)%26,w[i]^=ans%(1<<30);
        if(s[1]==s[i]) add(w[i],1);
        modify(1,n,i,w[i],root),ans=ans+query(1,i,1,n,root),pos=nxt[i-1];
        while(pos&&s[pos+1]!=s[i]) pos=nxt[pos];
        nxt[i]=pos+(s[pos+1]==s[i]),col[i-1]=s[i];
        for(int j=0;j<26;++j) fa[i][j]=fa[nxt[i]][j];
        fa[i][col[nxt[i]]]=nxt[i];
        for(int c=0;c<26;++c)
        {
            if(c==s[i]) continue;
            for(int j=fa[i-1][c];j;j=fa[j][c])
                add(query(i-j,i-1,1,n,root),-1);
        }
        add(w[i],update(w[i])),ans=ans+val,write(ans);
    }
    return 0;
}

CF1286E Fedya the Potter Strikes Back

标签:getc   read   map   fine   return   颜色不同   scanf   产生   main   

原文地址:https://www.cnblogs.com/lhm-/p/13773921.html

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