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 }