bzoj4504 k个串 kstring 可持久化线段树 (标记永久化)

【fjwc2015】k个串 kstring

【题目描述】

兔子们在玩k个串的游戏。首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)。

兔子们想知道,在这个数字序列所有连续的子串中,按照以上方式统计其所有数字之和,第k大的和是多少。

【输入格式】

第一行,两个整数n和k,分别表示长度为n的数字序列和想要统计的第k大的和

接下里一行n个数a_i,表示这个数字序列

【输出格式】

一行一个整数,表示第k大的和

【样例输入】

7 5

3 -2 1 2 2 1 3 -2

【样例输出】

4

【数据范围】

对于20%的数据,1 <= n <= 2000

对于另外20%的数据,0 <= a_i <= 10^9

对于100%的数据,1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9

数据保证存在第k大的和

 

题解:

  理解要紧,很简单的。

  一开始以为没有地方可以提交,结果发现bzoj上就有,

  可以rt[i]表示以i为左端点的区间。

  nxt[i]表示a[i]下一次出现的位置。

  发现rt[i]对于rt[i-1],发现就是在i-----nxt[i]-1这些位置都减去a[i],

  然后,然后对于i这个位置需要变为-inf,因为无法取到。

  然后先建辅助树rt[0],即永久性flag标记打上去的区间修改,然后再以-inf,那个位置再建出

  rt[i]即可,然后进行k次操作,用堆来维护即可。

 

  1 #include<cstring>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cstdio>
  6 #include<map>
  7 #include<queue>
  8 
  9 #define lson tr[p].ls
 10 #define rson tr[p].rs
 11 #define N 100007
 12 #define ll long long
 13 using namespace std;
 14 const ll inf=2000000000000007;
 15 inline ll read()
 16 {
 17     ll x=0,f=1;char ch=getchar();
 18     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 19     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
 20     return x*f;
 21 }
 22 
 23 ll n,k,sz;
 24 ll a[N],id[N],b[N],rt[N*3],nxt[N];
 25 map<ll,ll>p;
 26 struct Node
 27 {
 28     ll ls,rs,mx,flag,tag;
 29 }tr[N*100];
 30 struct Date
 31 {
 32     ll num,wei,rt;
 33     friend bool operator < (Date x,Date y)
 34     {
 35         return x.num<y.num;
 36     }
 37 };
 38 priority_queue<Date>q;
 39 
 40 bool cmp(ll x,ll y)
 41 {
 42     if (a[x]==a[y]) return x<y;
 43     else return a[x]<a[y];
 44 }
 45 inline void update(ll p)
 46 {
 47     if (tr[lson].mx+tr[lson].tag>tr[rson].mx+tr[rson].tag) tr[p].mx=tr[lson].mx+tr[lson].tag,tr[p].flag=tr[lson].flag;
 48     else tr[p].mx=tr[rson].mx+tr[rson].tag,tr[p].flag=tr[rson].flag;
 49 }
 50 void build(ll &p,ll l,ll r)
 51 {
 52     p=++sz;
 53     if (l==r)
 54     {
 55         tr[p].mx=b[l];
 56         tr[p].flag=l;
 57         return;
 58     }
 59     ll mid=(l+r)>>1;
 60     build(tr[p].ls,l,mid),build(tr[p].rs,mid+1,r);
 61     update(p);
 62 }
 63 void build_new(ll yl,ll &xz,ll l,ll r,ll x,ll y,ll z)
 64 {
 65     xz=++sz,tr[xz]=tr[yl];
 66     if (l==x&&r==y)
 67     {
 68         tr[xz].tag+=z;
 69         return;
 70     }
 71     //标记永久化。 
 72     ll mid=(l+r)>>1;
 73     if (y<=mid) build_new(tr[yl].ls,tr[xz].ls,l,mid,x,y,z);
 74     else if (x>mid) build_new(tr[yl].rs,tr[xz].rs,mid+1,r,x,y,z);
 75     else build_new(tr[yl].ls,tr[xz].ls,l,mid,x,mid,z),build_new(tr[yl].rs,tr[xz].rs,mid+1,r,mid+1,y,z);
 76     update(xz);
 77 }
 78 int main()
 79 {
 80     freopen("kstring.in","r",stdin);
 81     freopen("kstring.out","w",stdout);
 82     
 83     n=read(),k=read();
 84     for (ll i=1;i<=n;i++)
 85         a[i]=read(),id[i]=i;
 86     sort(id+1,id+n+1,cmp);
 87     a[0]=-inf;
 88     for (ll i=1;i<=n;i++)
 89         if (a[id[i]]!=a[id[i-1]]) b[id[i]]=a[id[i]];
 90     for (ll i=1;i<=n;i++) b[i]+=b[i-1];
 91     build(rt[1],1,n);
 92     for (ll i=n;i>=1;i--)
 93     {
 94         if (!p[a[i]]) nxt[i]=n+1;
 95         else nxt[i]=p[a[i]];
 96         p[a[i]]=i;
 97     }
 98     for (ll i=2;i<=n;i++)
 99     {
100         if (i>nxt[i-1]-1) build_new(rt[i-1],rt[0],1,n,1,n,0);
101         else build_new(rt[i-1],rt[0],1,n,i,nxt[i-1]-1,-a[i-1]);
102         build_new(rt[0],rt[i],1,n,i-1,i-1,-inf);
103     }
104     for (ll i=1;i<=n;i++)
105         q.push((Date){tr[rt[i]].mx+tr[rt[i]].tag,tr[rt[i]].flag,i});
106     for(ll i=1;i<k;i++)
107     {
108         Date now=q.top();q.pop();
109         build_new(rt[now.rt],rt[n+i],1,n,now.wei,now.wei,-inf);
110         q.push((Date){tr[rt[n+i]].mx,tr[rt[n+i]].flag,i+n});
111     }
112     Date now=q.top();
113     printf("%lld\n",now.num);
114 }

 

 

 

  

 

 

 

posted @ 2017-12-18 21:25  Kaiser-  阅读(544)  评论(0编辑  收藏  举报