Bzoj4504: K個串
阿新 • • 發佈:2018-06-21
AD back scrip 序列 pda hint type cond discuss
Submit: 517 Solved: 200
[Submit][Status][Discuss]
3 -2 1 2 2 1 3 -2
題解: 我們考慮到查詢區間類不同數目的個數在線做法是主席樹維護,然後我們可以維護出每個位置的值產生貢獻的範圍,然後相當於主席樹維護了以i為右端點,[j,i]的不同數字的和 然後考慮到這題的K在可接受的範圍內 所以我們采用分裂的方式 即維護每個右端點裏面的最大值 然後優先隊列維護五元組 找出第K大 時間復雜度是(n+k)logn
#include <bits/stdc++.h> #define ll long long #define pii pair<ll,int> const int MAXN=1e5+10; const ll inf=1e18; using namespace std; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar(); return f*x; } int n,k; typedef struct node{ int l,r,pos;ll sum,maxx; }node; node d[MAXN*101]; int rt[MAXN]; int cnt;int cnt1; void up(int x,int l,int r){ d[x].maxx=d[d[x].l].maxx;d[x].pos=l; if(d[x].l)d[x].pos=d[d[x].l].pos; if(d[d[x].r].maxx>d[x].maxx)d[x].maxx=d[d[x].r].maxx,d[x].pos=d[d[x].r].pos; if(!d[x].pos)d[x].pos=((l+r)>>1)+1; d[x].maxx+=d[x].sum; } void update(int &x,int y,int l,int r,int ql,int qr,ll vul){ // cout<<l<<"====="<<r<<" "<<vul<<" "<<ql<<" "<<qr<<endl; x=++cnt;d[x]=d[y]; if(!d[x].pos)d[x].pos=l; if(ql<=l&&r<=qr){d[x].sum+=vul;d[x].maxx+=vul;return ;} int mid=(l+r)>>1; if(ql<=mid)update(d[x].l,d[y].l,l,mid,ql,qr,vul); if(qr>mid)update(d[x].r,d[y].r,mid+1,r,ql,qr,vul); up(x,l,r); // cout<<d[x].maxx<<"::::"<<" "<<d[x].pos<<" "<<ql<<" "<<qr<<endl; } pii aim;bool flag; void querty(int x,int l,int r,int ql,int qr,ll key){ // cout<<l<<" "<<r<<" "<<ql<<" "<<qr<<" "<<aim.first<<" "<<aim.second<<" "<<d[x].maxx<<endl; if(!x){ if(!flag){ aim.first=key,aim.second=max(l,ql),flag=1; } else{ if(aim.first<key)aim.first=key,aim.second=max(l,ql); } return ; } if(ql<=l&&r<=qr){ if(!flag)aim.first=key+d[x].maxx,aim.second=d[x].pos,flag=1; else{if(aim.first<key+d[x].maxx)aim.first=key+d[x].maxx,aim.second=d[x].pos;} return ; } int mid=(l+r)>>1; if(ql<=mid)querty(d[x].l,l,mid,ql,qr,key+d[x].sum); if(qr>mid)querty(d[x].r,mid+1,r,ql,qr,key+d[x].sum); } vector<ll>vec; ll a[MAXN]; int pre[MAXN]; typedef struct Node{ int l,r,rx,pos;ll vul; friend bool operator<(Node aa,Node bb){ return aa.vul<bb.vul; } }Node; priority_queue<Node>que; int main(){ n=read();k=read(); for(int i=1;i<=n;i++)a[i]=read(),vec.push_back(a[i]); sort(vec.begin(),vec.end()); int sz=unique(vec.begin(),vec.end())-vec.begin(); for(int i=1;i<=n;i++)a[i]=lower_bound(vec.begin(),vec.begin()+sz,a[i])-vec.begin()+1; for(int i=1;i<=n;i++){update(rt[i],rt[i-1],1,n,pre[a[i]]+1,i,vec[a[i]-1]);pre[a[i]]=i;} for(int i=1;i<=n;i++){ Node t;t.l=1;t.r=i;t.rx=i; aim.first=0;aim.second=0; flag=0;querty(rt[i],1,n,1,i,0); t.pos=aim.second;t.vul=aim.first; // cout<<t.pos<<"======------"<<t.vul<<endl; que.push(t); } for(int i=1;i<k;i++){ Node t=que.top();que.pop(); if(t.pos>t.l){ Node t1;t1.l=t.l;t1.r=t.pos-1;t1.rx=t.rx; flag=0;querty(rt[t.rx],1,n,t.l,t.pos-1,0); t1.pos=aim.second;t1.vul=aim.first; que.push(t1); } if(t.pos<t.r){ Node t2;t2.l=t.pos+1;t2.r=t.r;t2.rx=t.rx; flag=0;querty(rt[t.rx],1,n,t.pos+1,t.r,0); t2.pos=aim.second;t2.vul=aim.first; que.push(t2); } } printf("%lld\n",que.top().vul); return 0; }
4504: K個串
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 517 Solved: 200
[Submit][Status][Discuss]
Description
兔子們在玩k個串的遊戲。首先,它們拿出了一個長度為n的數字序列,選出其中的一 個連續子串,然後統計其子串中所有數字之和(註意這裏重復出現的數字只被統計一次)。 兔子們想知道,在這個數字序列所有連續的子串中,按照以上方式統計其所有數字之和,第 k大的和是多少。
Input
第一行,兩個整數n和k,分別表示長度為n的數字序列和想要統計的第k大的和 接下裏一行n個數a_i,表示這個數字序列
Output
一行一個整數,表示第k大的和
Sample Input
7 53 -2 1 2 2 1 3 -2
Sample Output
4HINT
1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9數據保證存在第 k 大的和
Bzoj4504: K個串