K Seq HihoCoder - 1046 || BZOJ4504 k个串

这题与超级钢琴类似,然而重复的不重复计算贡献。。

那么先求出数组nxt,nxt[i]表示第i个元素之后的第一个与其相等的元素的下标,不存在则nxt[i]=0

考虑取的区间左端点为1时的情况。

将读入序列a中相等元素都只保留最先出现的,其余变为0,然后求前缀和,得到数组b。

此时可以知道,设f(l,r)为取下标在[l,r]区间内数时的答案,那么f(1,r)=b[r]。

考虑取的区间左端点为2时的情况。如何维护b数组,使得新的b数组也满足f(2,r)=b[r]?

手模样例区间左端点为1和2时符合要求的b。

样例:

7 5
3 -2 1 2 2 1 3

l=1:  3  1  2 4 4 4 4
l=2:  0  -2 -1 1 1 1 4

可以发现,做的操作相当于将b数组内下标在[1,nxt[1]-1]区间内的数减了(原来的)b[1]。

进一步推出,左端点为l时的b数组变到左端点l+1的b数组,就相当于将下标在[l,nxt[l]-1]区间内的数减了(原来的)b[l]。

(当然如果nxt[i]=0,那么就是将[l,n]内减b[l])

因此,可以用可持久化线段树处理出左端点为每一个位置时的b数组。可持久化线段树如果要传标记的话常数会很大(复杂度应该是对的...大概吧?),所以可以标记永久化

(不知道为什么网上的标记永久化那么长?吓得我还以为自己写错了233333)

(我写标记永久化时候困难重重,最后发现标记含义的定义还是类比普通线段树最容易实现(就是除当前节点外,以当前节点为根的子树内所有点的对应值都应加上当前节点的加法tag),另外给标记和记录的值一个明确的定义对于写清楚代码非常重要)

这样子之后就可以用类似超级钢琴的做法去做了...才怪。难道你真的跟我一样想要去写可持久化的带区间修改的区间第k大这样子一看就不靠谱的东西?

可以发现每一次对给定某一个b数组的查询,每次的区间都是一样的,一定是第一次第1大,第二次第2大,...

当然就可以用超级钢琴的后一种做法去做了(优先队列维护一下哪个b数组,哪一段区间的最大值是多少,在哪里,当某一段区间最大值被取出后,把该区间除了最大值所在位置剩下的最多两段取最大值放回优先队列)。‘

(似乎也可以考虑暴力将原来的最大值加一个-inf?这样子下一次查找找到的就是该区间的次大啦(我没试过))

错误记录:

1.不知道为什么想到去维护最小值了,怎么过的样例啊

2.82-83行i+1写成i

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<queue>
  4 #include<tr1/unordered_map>
  5 #define inf 0x3f3f3f3f3f3f3f3f
  6 #define mid ((l+r)>>1)
  7 using namespace std;
  8 using namespace tr1;
  9 typedef long long LL;
 10 typedef pair<LL,LL> P;
 11 LL lc[30000010],rc[30000100],addv[30000100],mem;
 12 //addv[i]表示i区间加法tag
 13 P maxn[30000100];//一对值:区间(只考虑自身及其下节点的标记)的最大值及下标
 14 LL L,R,x;
 15 LL root[100100],nxt[100100],a[100100],b[100100];
 16 tr1::unordered_map<LL,LL> ttt1;
 17 void build(LL l,LL r,LL &num)
 18 {
 19     num=++mem;
 20     if(l==r)    {maxn[num]=P(b[l],l);return;}
 21     build(l,mid,lc[num]);build(mid+1,r,rc[num]);
 22     maxn[num]=max(maxn[lc[num]],maxn[rc[num]]);
 23 }
 24 void addx(LL l,LL r,LL &num)
 25 {
 26     LL t=num;num=++mem;lc[num]=lc[t];rc[num]=rc[t];maxn[num]=maxn[t];addv[num]=addv[t];
 27     if(L<=l&&r<=R)
 28     {
 29         addv[num]+=x;maxn[num].first+=x;
 30         return;
 31     }
 32     if(L<=mid)    addx(l,mid,lc[num]);
 33     if(mid<R)    addx(mid+1,r,rc[num]);
 34     maxn[num]=max(maxn[lc[num]],maxn[rc[num]]);
 35     maxn[num].first+=addv[num];
 36 }
 37 P query(LL l,LL r,LL num)
 38 {
 39     if(L<=l&&r<=R)    return maxn[num];
 40     P ans=P(-inf,1);
 41     if(L<=mid)    ans=max(ans,query(l,mid,lc[num]));
 42     if(mid<R)    ans=max(ans,query(mid+1,r,rc[num]));
 43     ans.first+=addv[num];
 44     return ans;
 45 }
 46 struct Info
 47 {
 48     Info(LL a=0,LL b=0,LL c=0,LL d=0,LL e=0)
 49         :ans(a),l(b),r(c),st(d),pos(e)
 50     {}
 51     LL ans,l,r,st,pos;
 52     //root[st]中,[l,r]内最大值是ans,在pos位置
 53     friend bool operator<(const Info &a,const Info &b)
 54     {
 55         return a.ans<b.ans;
 56     }
 57 };
 58 LL n,k;
 59 priority_queue<Info> q;
 60 int main()
 61 {
 62     LL i;P t;Info t2;
 63     scanf("%lld%lld",&n,&k);
 64     for(i=1;i<=n;i++)    scanf("%lld",&a[i]);
 65     for(i=1;i<=n;i++)
 66     {
 67         b[i]=b[i-1];
 68         if(ttt1.count(a[i])==0)
 69             b[i]+=a[i];
 70         else
 71             nxt[ttt1[a[i]]]=i;
 72         ttt1[a[i]]=i;
 73     }
 74     build(1,n,root[0]);
 75     L=1,R=n,t=query(1,n,root[0]);
 76     q.push(Info(t.first,1,n,0,t.second));
 77     for(i=1;i<n;i++)
 78     {
 79         root[i]=root[i-1];
 80         L=i,R=i,x=-query(1,n,root[i]).first;
 81         L=i,R=nxt[i]?nxt[i]-1:n,addx(1,n,root[i]);
 82         L=i+1/**/,R=n,t=query(1,n,root[i]);
 83         q.push(Info(t.first,i+1,n,i,t.second));//
 84     }
 85     for(i=1;i<k;i++)
 86     {
 87         t2=q.top();q.pop();
 88         L=t2.l,R=t2.pos-1;
 89         if(L<=R)
 90         {
 91             t=query(1,n,root[t2.st]);
 92             q.push(Info(t.first,L,R,t2.st,t.second));
 93         }
 94         L=t2.pos+1,R=t2.r;
 95         if(L<=R)
 96         {
 97             t=query(1,n,root[t2.st]);
 98             q.push(Info(t.first,L,R,t2.st,t.second));
 99         }
100     }
101     t2=q.top();
102     printf("%lld",t2.ans);
103     return 0;
104 }

原文地址:https://www.cnblogs.com/hehe54321/p/8598141.html

时间: 2025-01-17 20:47:09

K Seq HihoCoder - 1046 || BZOJ4504 k个串的相关文章

【LeetCode-面试算法经典-Java实现】【023-Merge k Sorted Lists(合并k个排好的的单链表)】

[023-Merge k Sorted Lists(合并k个排好的的单链表)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 题目大意 合并k个排好的的单链表.分析和描述它的复杂性. 解题思路 使用小顶堆来实现,先将K个链表的头结点入堆,取堆顶元素,这个结点就是最小的,接

二分查找,查指定值、小于k的最大值,大于k的最大值

我们经常会用到二分查找 二分查找应该很多人都会写了,今天要写一个用二分查找找到小于k的最大值的时候看了很久不懂他设计的思路,后来想通了,记录一下. 所以这篇主要是讲 用二分查找找到小于k的最大值和大于k的最大值. 二分查找查找指定值 这个挺简单的,直接上代码吧 //获取值是k的位置,找不到则返回-1 public static int getK(int[] a, int k){ if(a.length == 0){ return -1; } int l = 0; int r = a.length

BZOJ4504 : K个串

从左往右枚举右端点,用一棵线段树维护每个左端点的去重后的区间和. 那么对于$a[r]$,需要在$[pre[a[r]]+1,r]$里区间加上$a[r]$. 将线段树可持久化,并维护区间最大值,就可以在线询问形如“给定$r$以及$a,b$”,问$l$在$[a,b]$里$[l,r]$的区间和的最大值的问题. 用一个大根堆维护五元组$(v,x,l,r,m)$,表示区间和为$v$,所在线段树根节点为$x$,所选左端点范围为$[l,r]$,选了$m$. 然后重复$k$次,每次取出堆顶,扩展出$[l,m-1]

LeetCode OJ:Merge k Sorted Lists(归并k个链表)

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 类似于归并2个链表,暴力一点的方法就是,每取出一个list就与以前的list归并返回merge后list,知道所有list merge完成. 但是可惜,这样做会TLE.贴下代码先: 1 /** 2 * Definition for singly-linked list. 3 * struct List

[LeetCode] Longest Substring with At Most K Distinct Characters 最多有K个不同字符的最长子串

Given a string, find the length of the longest substring T that contains at most k distinct characters. For example, Given s = “eceba” and k = 2, T is "ece" which its length is 3. 这道题是之前那道Longest Substring with At Most Two Distinct Characters的拓展

[LeetCode] Longest Substring with At Least K Repeating Characters 至少有K个重复字符的最长子字符串

Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times. Example 1: Input: s = "aaabb", k = 3 Output: 3 The longest substring is "aaa"

农行K宝不能使用 农行K宝导致光驱无法识别的解决方法

农行的K宝又不能用了 - 农行的K宝和IE8像是有仇似的 也不知道是驱动的原因还是IE的原因 反正经常性的无法识别这次的问题是:选择证书之后 提示无法连接 着手解决:先去农行网站 下载最新版的驱动 发现和我装的是一个版本 看来不是驱动的问题运行services.msc 查看Certificate Propagation服务和GP_CLT服务 也是启动状态 也不是服务的问题运行农行的客户端检测程序 告诉我"当前设置不影响网银使用" - -!这是怎么了--没办法了 进入PE 还原我前几天做

2014年美团校招之——输出字典序为第k的排列(0&lt;=k&lt;n!)

思路: 比如:n=4,k=6(k从0开始计数),那么就是从找第四个数,那么看规律 (第一队) 1234 1243 1324 1342 1423 1432 (第二队) 2134 2143 2314 2341 2413 2431 (第三队) .... 我们从第一个数字开始确定,由于确定第一个数了,那么后面的排列组合数是(n-1)!也就是6.问题就是如何确定第一个数,这里k=6,我们算出 k/n=1,说明这个数在第二队中. 那么我们应该把2移到最前面,此时排列就变成了2134.此时问题变为在第二队中找

[LeetCode] 340. Longest Substring with At Most K Distinct Characters 最多有K个不同字符的最长子串

Given a string, find the length of the longest substring T that contains at most k distinct characters. For example, Given s = “eceba” and k = 2, T is "ece" which its length is 3. 159. Longest Substring with At Most Two Distinct Characters 的拓展,1