zoukankan      html  css  js  c++  java
  • BZOJ 4504: K个串

    题目大意:

    求一个序列的第k大的子串和。

    题解:

    对于一个右端点找最优的左端点,扔进堆里。

    每次取堆顶,将这个右端点可以选择的左端点的区间分成两段,扔进堆里,重复k次。

    现在需要对于一个固定的右端点,左端点在一个区间里,求最大值。

    可持久化线段树上区间修改,不用标记永久化也可以过。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<queue>
    #define mp make_pair
    #define pr pair<long long,int>
    #define prr pair<pr,pr>
    #define fr first
    #define sc second
    using namespace std;
    int n,k,cnt,ls[10000005],rs[10000005],root[200005];
    long long tag[10000005];
    priority_queue<prr> q;
    map<int,int> pre;
    struct node{
    	long long val;
    	int id;
    }tree[10000005];
    void build(int &x,int l,int r){
    	x=++cnt;
    	tree[x]=(node){0,l};
    	if (l==r) return;
    	int mid=(l+r)>>1;
    	build(ls[x],l,mid);
    	build(rs[x],mid+1,r);
    }
    void add(int &now,int pre,long long key){
    	now=++cnt;
    	ls[now]=ls[pre],rs[now]=rs[pre],tree[now]=tree[pre],tag[now]=tag[pre]+key;
    	tree[now].val+=key;
    }
    void push_down(int x){
    	if (!tag[x]) return;
    	add(ls[x],ls[x],tag[x]);
    	add(rs[x],rs[x],tag[x]);
    	tag[x]=0;
    }
    void insert(int &now,int pre,int l,int r,int x,int y,int key){
    	if (l>y || r<x) return;
    	if (l>=x && r<=y){
    		add(now,pre,key);
    		return;
    	}
    	push_down(pre);
    	now=++cnt;
    	ls[now]=ls[pre],rs[now]=rs[pre],tree[now]=tree[pre];
    	int mid=(l+r)>>1;
    	insert(ls[now],ls[pre],l,mid,x,y,key);
    	insert(rs[now],rs[pre],mid+1,r,x,y,key);
    	if (tree[rs[now]].val>tree[ls[now]].val) tree[now]=tree[rs[now]];
    	else tree[now]=tree[ls[now]];
    }
    node query(int now,int l,int r,int x,int y){
    	if (!now) return (node){-1ll<<60,0};
    	if (l>y || r<x) return (node){-1ll<<60,0};
    	if (l>=x && r<=y) return tree[now];
    	push_down(now);
    	int mid=(l+r)>>1;
    	node max1=query(ls[now],l,mid,x,y);
    	node max2=query(rs[now],mid+1,r,x,y);
    	if (max1.val>max2.val) return max1;
    	else return max2;
    }
    void insert(int x,int l,int r){
    	if (l>r) return;
    	node sum=query(x,1,n,l,r);
    	q.push(mp(mp(sum.val,x),mp(l,r)));
    }
    int main(){
    	scanf("%d%d",&n,&k);
    	build(root[0],1,n);
    	for (int i=1; i<=n; i++){
    		int x;
    		scanf("%d",&x);
    		insert(root[i],root[i-1],1,n,pre[x]+1,i,x);
    		pre[x]=i;
    		insert(root[i],1,i);
    	}
    	long long sum;
    	while (k--){
    		sum=q.top().fr.fr;
    		int id=q.top().fr.sc,l=q.top().sc.fr,r=q.top().sc.sc;
    		q.pop();
    		int mid=query(id,1,n,l,r).id;
    		insert(id,l,mid-1);
    		insert(id,mid+1,r);
    	}
    	printf("%lld
    ",sum);
    	return 0;
    }
    

      

     

  • 相关阅读:
    JavaScript 电话手机号码正则表达式
    查找和删除sqlserver数据库中的重复记录
    配置文件app.config
    数据类型 ntext 和 varchar 在 equal to 运算符中不兼容的错误信息
    用jscript处理repeater生成的表格, 实现分页打印
    我在Repeater控件中有CheckBox控件,我怎么能选中CheckBox控件后,Repeater控件重新绑定一下?
    种方式遍历repeater中的CheckBox全选
    Repeater导出为excel格式
    给Repeater、Datalist和Datagrid增加自动编号
    js中对datagrid ,repeater的checkbox进行全选反选
  • 原文地址:https://www.cnblogs.com/silenty/p/8760876.html
Copyright © 2011-2022 走看看