4504: K个串 主席树+优先队列
2016-05-05 21:13
183 查看
这道题因为有一个数在序列中出现多次只算一次的限制。我们可以这样搞。假设在当前题意下求给定右端点的区间最值。那么我们可以预处理出每个数前一次出现的位置pre[i] 。接下来从左到右加入每一个值,就是在 pre[i] + 1 —— i 这个区间内加上 v[i] 的值,这样就可以得到以当前 i 点为右端点的各个区间的值(很明显维护一下最值就好了)。接下来很明显有n个版本的线段树(如果你说一开始那个空的线段树也算一个版本的话,就有n+1个),那就要用主席树动态开点。而取第K大值的操作有点像超级钢琴,不过在这里要维护5元组吧! 分别是 区间左端点, 区间右端点, 区间最值点, 区间最值, 线段树版本。 没了!就这样!
#include<cstdio> #include<queue> #include<iostream> #include<map> #define rep(i,j,k) for(register int i = j; i <= k; i++) #define maxn 100005 #define ll long long #define inf 1ll * 10000000 * 10000000 using namespace std; inline int read() { int s = 0, t = 1; char c = getchar(); while( !isdigit(c) ) { if( c == '-' ) t = -1; c = getchar(); } while( isdigit(c) ) s = s * 10 + c - 48, c = getchar(); return s * t; } int ql, qr, d, tot = 0, rot[maxn], c[maxn*100][2], pos[maxn*100]; ll sum[maxn*100], v[maxn*100]; #define lc c[k][0] #define rc c[k][1] #define mid ((l+r)>>1) inline void build(int l,int r,int &k) { k = ++tot; pos[k] = l; if( l == r ) return; build(l,mid,lc); build(mid+1,r,rc); } inline void update(int &k,int pre,int l,int r) { k = ++tot; sum[k] = sum[pre], v[k] = v[pre]; lc = c[pre][0], rc = c[pre][1]; if( ql <= l && r <= qr ) { sum[k] += d; v[k] += d; pos[k] = pos[pre]; return; } if( ql <= mid ) update(lc,c[pre][0],l,mid); else lc = c[pre][0]; if( qr > mid ) update(rc,c[pre][1],mid+1,r); else rc = c[pre][1]; if( sum[lc] > sum[rc] ) sum[k] = sum[lc] + v[k], pos[k] = pos[lc]; else sum[k] = sum[rc] + v[k], pos[k] = pos[rc]; } int wh; ll maxl; inline void querymx(int k,int l,int r, ll pd) { if( ql <= l && r <= qr ) { if( sum[k] + pd > maxl ) maxl = sum[k] + pd, wh = pos[k]; return; } if( ql <= mid ) querymx(lc,l,mid,pd+v[k]); if( qr > mid ) querymx(rc,mid+1,r,pd+v[k]); } inline void out(int k,int l,int r,ll pd) { if( l == r ) { cout<<pd+sum[k]<<" "; return; } out(lc,l,mid,pd+v[k]); out(rc,mid+1,r,pd+v[k]); } map<int,int> last; int pre[maxn], val[maxn]; struct node{ int l, r, id, pos; ll v; bool operator < (const node&rhs) const { return v < rhs.v; }; }; priority_queue<node> q; #define mkp(i,j,k,l,d) (node){i,j,k,l,d} int main() { int n = read(), k = read(); rep(i,1,n) val[i] = read(), pre[i] = last[val[i]], last[val[i]] = i;; build(1,n,rot[0]); rep(i,1,n) { ql = pre[i] + 1, qr = i, d = val[i]; update(rot[i],rot[i-1],1,n); ql = 1, qr = i; maxl = -inf; querymx(rot[i],1,n,0); //out(rot[i],1,n,0); cout<<endl; q.push(mkp(1,i,i,wh,maxl)); } rep(i,1,k-1) { node a = q.top(); q.pop(); int l = a.l, r = a.r, at = a.pos, id = a.id; if( l < at ) { ql = l, qr = at - 1; maxl = -inf; querymx(rot[id],1,n,0); q.push(mkp(ql,qr,id,wh,maxl)); } if( at < r ) { ql = at + 1, qr = r; maxl = -inf; querymx(rot[id],1,n,0); q.push(mkp(ql,qr,id,wh,maxl)); } } node a = q.top(); printf("%lld\n", a.v); return 0; }
相关文章推荐
- 面向对象设计原则之二:开放封闭原则
- FZU 2038 Another Postman Problem【思维】
- 利用mybatis-generator自动生成代码
- 【HUSTOJ】1055: 字符图形11-字母正三角
- 大数据学习笔记3-近邻搜索
- SPOJ HIGH (生成树计数)
- Android----ObjectAnimator and ValueAnimator
- 第十周项目—阅读程序,写出执行结果(2)
- 定时器
- CRF(条件随机场)
- 在tomcat上全手工部署Servlet3.0
- 【前端】screenX/Y, clientX/Y, pageX/Y 的区别
- LeetCode-10. Regular Expression Matching
- NYOJ-183赚钱啦,bellman//spfa水过,,题还是蛮变态的赶脚~~
- 关于View.getHeight和getWidth为0的解决方案(待深入学习)
- 原型模式(Prototype)以及深浅复制
- 快速排序复习
- Hadoop2.4.1伪分布式搭建
- leetcode_097 Interleaving String
- 详解mysql int数字类型的长度值大小上限