【hihocoder 1046】K Seq(线段树)

来源:互联网 发布:疲劳检测算法 编辑:程序博客网 时间:2024/05/22 08:23

传送门

I Think

    题意:求一个串子串和(定义为该串内不重复的元素和)第k大
    算法:可持久化线段树+动态开点
    思路:手动样例计算以第1、2、3……n个元素为串首的多个子串和,以S[i][]记以第i个元素为首的子串和们,预处理出每一个元素下一次出现的位置pos[i],会发现对于 j ∈ [i, pos − 1],S[i][j] 的元素值就等于 S[i − 1][j] 的元素值减去 val[i − 1],其他下标的元素的值不变。
    于是我们对每个元素建立线段树,维护以它为首的子串长度值。找第k大时先把每个位置的线段树的最大值放进一个堆里,每次取出一个最大值并将其原位置的值改为无穷小。(注意inf要开大)重复k-1次该过程即可。
    在维护线段树中最大值时Add的标记mk是没有下传的,因为每次Up加上了mk,递归回到根的过程中总会加上这个标记,这种维护最值而不是区间和的情况可以考虑标记不下传。

Code

#include<queue>#include<cstdio>#include<cstring>#include<algorithm>#define f first#define s secondusing namespace std;typedef long long LL;const int sm = 1e5+10;const int sn = 1e7;const LL inf = 1e14+50;template <typename T> T Max(T x,T y) { return x>y?x:y; } template <typename T> void read(T &x) {    char ch=getchar();int f=1;x=0;    while(ch>'9'||ch<'0') { if(ch=='-') f=-1;ch=getchar(); }    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); x*=f;}priority_queue<pair<LL,int > >que;int n,k,tot,cnt;int Ls[sn],Rs[sn];LL S[sm],mx[sn],mk[sn],pos[sn];//pos[sn]int A[sm],B[sm],T[sm],ex[sm],nxt[sm];int Hash(int x) {    return lower_bound(B+1,B+cnt+1,x)-B;}void Up(int rt) {    mx[rt]=Max(mx[Ls[rt]],mx[Rs[rt]])+mk[rt];//mk[rt]    pos[rt]=(mx[Ls[rt]]>mx[Rs[rt]])?pos[Ls[rt]]:pos[Rs[rt]];}void Build(int &rt,int l,int r) {    rt=++tot;    if(l==r) {        mx[rt]=S[l],pos[rt]=l;return;    }    int m=(l+r)>>1;    Build(Ls[rt],l,m);    Build(Rs[rt],m+1,r);    Up(rt);}void Modify(int &rt,int l,int r,int p) {//不要掉&    int pt=rt;rt=++tot;    mx[rt]=mx[pt],pos[rt]=pos[pt],mk[rt]=mk[pt],Ls[rt]=Ls[pt],Rs[rt]=Rs[pt];    if(l==r) { mx[rt]=mk[rt]=-inf; return; }    int m=(l+r)>>1;    if(p<=m) Modify(Ls[rt],l,m,p);    else Modify(Rs[rt],m+1,r,p);    Up(rt);}void Add(int pre,int &rt,int l,int r,int a,int b,int val) {    rt=++tot,mx[rt]=mx[pre],mk[rt]=mk[pre];    pos[rt]=pos[pre],Ls[rt]=Ls[pre],Rs[rt]=Rs[pre];    if(a<=l&&r<=b) {        mk[rt]+=val,mx[rt]+=val; return ;    }    int m=(l+r)>>1;    if(a<=m) Add(Ls[pre],Ls[rt],l,m,a,b,val);    if(b> m) Add(Rs[pre],Rs[rt],m+1,r,a,b,val);    Up(rt);}int main() {    read(n),read(k);        for(int i=1;i<=n;++i) read(A[i]),B[i]=A[i],nxt[i]=n+1;    sort(B+1,B+n+1);    cnt=unique(B+1,B+n+1)-B;    for(int i=1,hsh;i<=n;++i) {        hsh=Hash(A[i]);        if(!ex[hsh]) S[i]=S[i-1]+A[i],ex[hsh]=i;        else nxt[ex[hsh]]=i,ex[hsh]=i,S[i]=S[i-1];    }    Build(T[1],1,n);    que.push(make_pair(mx[T[1]],T[1]));    for(int i=2;i<=n;++i) {        Add(T[i-1],T[i],1,n,i,nxt[i-1]-1,-1*A[i-1]);        Modify(T[i],1,n,i-1);        que.push(make_pair(mx[T[i]],T[i]));    }    for(int i=1,p;i<k;++i) {        p=que.top().s,que.pop();        Modify(p,1,n,pos[p]);        que.push(make_pair(mx[p],p));    }    printf("%lld\n",que.top().f);    return 0;}
阅读全文
0 0
原创粉丝点击