【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
- 【hihocoder 1046】K Seq(线段树)
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树)
- bzoj 1798: [Ahoi2009]Seq 维护序列seq (线段树)
- bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树)
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)
- BZOJ 题目1798: [Ahoi2009]Seq 维护序列seq(双标记线段树)
- (1798: [Ahoi2009]Seq 维护序列seq)<线段树乘法操作>
- bzoj 1798 维护序列 seq (线段树)
- BZOJ 1798-维护序列seq(线段树区间更新)
- COGS-2275 [HEOI 2016] seq(树状数组+线段树)
- 【BZOJ1798】[Ahoi2009]Seq 维护序列seq 线段树
- bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树
- BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树
- 【bzoj1798】[Ahoi2009]Seq 维护序列seq 线段树
- 1798: [Ahoi2009]Seq 维护序列seq 线段树
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq|线段树
- 【BZOJ1798】[Ahoi2009]Seq 维护序列seq 【线段树】
- [线段树] BZOJ1798: [Ahoi2009]Seq 维护序列seq
- zookeeper 安装的三种模式
- Find The Multiple ——深搜POJ
- 【资源】2014斯坦福机器学习视频+西瓜书pdf及答案
- node.js开发:在windows环境下安装node与环境配置
- WINFORM调用百度翻译API
- 【hihocoder 1046】K Seq(线段树)
- MySQL使用IP地址登录 ERROR 1045 (28000): Access denied for user 'root'@'11.1.81.117' (using passwor:YES)
- JSON 字符串 单引号双引号 处理
- 齐次坐标,多视图几何,三维重建数学
- [qt for android]构建项目时,出现“过程试图写入的管道不存在”错误的解决方法
- easyui 多表头设置以及绑定数据
- BLE-NRF51822教程10—动态密码(配对码)
- 动画animation
- Restful api 设计最佳实践