[UNR #6]稳健型选手
稳健型选手
题解
我是废物
首先看到这题,先考虑我们QAQ\rm QAQQAQ蚤的最优策略是什么。
显然,原题的选择问题相当于可以抽象转化一下,∀i∈[1,n2]\forall i\in[1,\frac{n}{2}]∀i∈[1,2n],前2i2i2i个中最多选择iii个。
这个还是比较好证明的,因为当你选了iii个后,另外一个人必然在[1,2i][1,2i][1,2i]中选了iii个,这样你在这个区间内最多也只能选iii个了。
这样我要贪心选的话显然是考虑从后往起那算,每次选择当前能选择的后缀中最大的一个数,这显然是正确的。
这样的话我们也就能够O(nlogn)O\left(n\log n\right)O(nlogn)地处理一个长为nnn的序列到了,那么在面对多次询问时我们又能有什么优化方法呢?
不妨考虑回滚莫队,在已经处理了一个完整的前缀的答案后,如果我们现在要在这个串加入不超过BBB的点,会对答案产生怎样的影响。
显然,这BBB个点本身是会产生B2\frac{B}{2}2B个能新加入的点的。我们可以先将这些点用上面的方法先算出来,然后剩下了一些点是在后面不能加入的,但它们还是可以替换掉前面已经加入的点。
我们可以把前面最小的B2\frac{B}{2}2B个已经加入的点拿出来,跟后面尚未加入的这B2\frac{B}{2}2B个点归并,从而得到哪些前面的点会被后面的点替换掉。
这样的话,我们只需要对前面维护一个已经加入节点的权值线段树即可。
时间复杂度也就被优化到了O(nnlogn)O\left(n\sqrt{n}\log n\right)O(nnlogn)。
如果你把后面这部分每个后缀所对应的尚未加入的点也利用线段树预处理出来的话,实际上是可以达到O(nnlogn)O\left(n\sqrt{n\log n}\right)O(nnlogn),不过好像都过不了n⩽2×105n\leqslant 2\times 10^5n⩽2×105。
尝试继续优化。
显然,上面算法的重点是在合并两个已经做好选择的串。
如果在串AAA后面接上串BBB的话,相当于是让串BBB中一些没能被选择的点优化掉串AAA中的一些被选择了的点。
很明显,如果两个东西我们都是利用线段树维护的话,完全可以在线段树上二分求解。
只要找到最大的后缀,使得两棵权值线段树上这个后缀的数的数量加起来不超过原来选择的数的数量即可,这东西好搞。
所以我们完全可以尝试利用分治的方法解决这个问题。
对于[l,mid][l,mid][l,mid]中的部分,可以利用可持久化线段树处理出来对于每个左端点,到midmidmid为止的串里哪些点被选了。
同样,对于(mid,r](mid,r](mid,r]的部分,也可以通过类似的方法求出哪些点没有被选。
那么跨越midmidmid的询问,就能够直接把两边的线段树拿出来一起二分,求出哪些点会被替代,再加上先预处理的没别影响的点的总和就能得到答案了。
显然,这样每个位置都最多只会被加入logn\log nlogn次,大大优化了时间复杂度。
总时间复杂度O(nlog2n)O\left(n\log^2 n\right)O(nlog2n)。
源码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,LL> pii;
#define MAXN 200005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lowbit(x) (x&-x)
const int mo=998244353;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=15;
const int INF=0x3f3f3f3f;
const double Pi=acos(-1.0);
const double eps=1e-9;
const int lim=1000000;
const int orG=3,ivG=332748118;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,q,a[MAXN],root[MAXN],ord[MAXN],p[MAXN];
LL summ[MAXN],ans[MAXN];
struct ming{int l,r;}s[MAXN];
struct node{int lson,rson,num;LL sum;};
vector<int>vec[MAXN<<2];
class SegmentTree{private:node tr[MAXN*40];int tot;public:void insert(int &now,int las,int l,int r,int ai,int aw){if(l>r||l>ai||r<ai)return ;tr[now=++tot]=tr[las];tr[now].num+=aw;tr[now].sum+=aw*a[ord[ai]];if(l==r)return ;int mid=l+r>>1;if(ai<=mid)insert(tr[now].lson,tr[las].lson,l,mid,ai,aw);if(ai>mid)insert(tr[now].rson,tr[las].rson,mid+1,r,ai,aw);}int queryL(int rt,int l,int r,int k){if(l==r)return l;int mid=l+r>>1;if(tr[tr[rt].lson].num>=k)return queryL(tr[rt].lson,l,mid,k);return queryL(tr[rt].rson,mid+1,r,k-tr[tr[rt].lson].num);}int queryR(int rt,int l,int r,int k){if(l==r)return l;int mid=l+r>>1;if(tr[tr[rt].rson].num>=k)return queryR(tr[rt].rson,mid+1,r,k);return queryR(tr[rt].lson,l,mid,k-tr[tr[rt].rson].num);}int ask(int x,int y,int l,int r,int k){if(l==r)return l;int mid=l+r>>1;int tmp=tr[tr[x].rson].num+tr[tr[y].rson].num;if(tmp>=k)return ask(tr[x].rson,tr[y].rson,mid+1,r,k);return ask(tr[x].lson,tr[y].lson,l,mid,k-tmp);}LL askSum(int rt,int l,int r,int al,int ar){if(l>r||l>ar||r<al||al>ar||!rt)return 0;if(al<=l&&r<=ar)return tr[rt].sum;int mid=l+r>>1;LL res=0;if(al<=mid)res+=askSum(tr[rt].lson,l,mid,al,ar);if(ar>mid)res+=askSum(tr[rt].rson,mid+1,r,al,ar);return res;}void clear(){for(int i=1;i<=tot;i++)tr[i].num=tr[i].sum=tr[i].lson=tr[i].rson=0;tot=0;}
}T;
#define lson (rt<<1)
#define rson (rt<<1|1)
void insert(int rt,int l,int r,int al,int ar,int aw){int mid=l+r>>1;if(al<=mid&&mid<ar){vec[rt].pb(aw);return ;}if(l==r){ans[aw]=a[l];return ;}if(ar<=mid)insert(lson,l,mid,al,ar,aw);if(al>mid)insert(rson,mid+1,r,al,ar,aw);
}
priority_queue<int>qq[2];
priority_queue<int,vector<int>,greater<int> >pq[2];
void sakura(int rt,int l,int r){int siz=vec[rt].size(),mid=l+r>>1;if(l^r)sakura(lson,l,mid),sakura(rson,mid+1,r);if(!siz)return ;while(!qq[0].empty())qq[0].pop();while(!qq[1].empty())qq[1].pop();for(int i=mid;i>=l;i--){if(i+2>mid)root[i]=0;else root[i]=root[i+2];qq[i&1].push(p[i]);if(i+1<=mid)qq[i&1].push(p[i+1]);T.insert(root[i],root[i],1,n,qq[i&1].top(),1),qq[i&1].pop();}while(!pq[0].empty())pq[0].pop();while(!pq[1].empty())pq[1].pop();for(int i=mid+1;i<=r;i++){if(i-2<=mid)root[i]=0;else root[i]=root[i-2];if(i==mid+1)T.insert(root[i],root[i],1,n,p[i],1);else{int x=p[i],y=p[i-1];if(x<y)swap(x,y);pq[i&1].push(x);summ[i]=summ[i-2]+a[ord[x]];int t=pq[i&1].top();if(t<y)pq[i&1].pop(),pq[i&1].push(y),summ[i]+=a[ord[y]]-a[ord[t]],y=t;T.insert(root[i],root[i],1,n,y,1);}}for(int i=0;i<siz;i++){int x=vec[rt][i],L=s[x].l,R=s[x].r;LL res=0;if(R-L+1&1)res+=a[R],R--;if(R>mid){int tmp=(mid-L)/2+1,t=T.ask(root[L],root[R],1,n,tmp);res+=T.askSum(root[L],1,n,t,n)+T.askSum(root[R],1,n,t,n)+summ[R];}else res+=T.askSum(root[L],1,n,1,n);ans[x]=res;}for(int i=l;i<=r;i++)root[i]=summ[i]=0;T.clear();
}
bool cmp(int x,int y){return a[x]<a[y];}
int main(){read(n);read(q);for(int i=1;i<=n;i++)read(a[i]),ord[i]=i;for(int i=1;i<=q;i++)read(s[i].l),read(s[i].r),insert(1,1,n,s[i].l,s[i].r,i);sort(ord+1,ord+n+1,cmp);for(int i=1;i<=n;i++)p[ord[i]]=i;sakura(1,1,n);for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);return 0;
}
谢谢!!!
[UNR #6]稳健型选手相关推荐
- 【UNR #6 C】稳健型选手(分治)(主席树)(二分)
稳健型选手 题目链接:UNR #6 C 题目大意 有一排卡牌,然后每次询问一个区间,问先手最多的分数. 玩法是先手后手轮流选一张牌拿走,先手任选,后手一定会选最左边的. 然后分数是拿的牌的分数和. 思 ...
- PSGAN——姿态稳健型可感知空间式生成对抗网络论文详细解读与整理
PSGAN--姿态稳健型可感知空间式生成对抗网络论文详细解读与整理 1.摘要 2.什么是PSGAN? 3.主要贡献 4.整体模块 5.目标函数 6.实验结果--部分化妆和插值化妆 7.定量比较 8.参 ...
- 小日期时间型_货币基金破2%?稳健型选手们来瞧瞧这类基金咯!
本文阅读约5min▲▲▲ 五一小长假Happy回来 投资债基的宝宝们不淡定了 居然5连跌! 好多局长的粉丝纷纷发来消息: "局长我好慌,该赎回吗?" (图片来源:wind 日期 2 ...
- 卖萌型选手——前缀和、二分
被数组越界支配两个小时的恐惧 题目描述 鸡尾酒在一场cf的div2比赛中被血虐,一道简单大模拟竟然一个半小时都没AC,认清自己的实力之后他选择做一名卖萌型选手.有一天鸡尾酒遇到了一个炒鸡喜欢的小姐姐, ...
- 作为一个非天才型选手,普通程序员如何升级打怪?
作者 | keypressingmonkey 译者 | 孙薇,责编 | 夕颜 出品 | CSDN(ID:CSDNnews) 非天才生存指南 承认这一点很难,我的正式简历上也不会有:我是一名普通的程序员 ...
- MacBook Pro最全快捷键指南——高效型选手必备
剪切.拷贝.粘贴和其他常用快捷键 Command-X:剪切所选项并拷贝到剪贴板. Command-C:将所选项拷贝到剪贴板. Command-V:将剪贴板的内容粘贴到当前文稿或应用中. Command ...
- 教育市场藏宝图:寻找机会和模式
http://www.sina.com.cn 2009年01月05日 18:39 <IT经理世界>杂志 新东方上市之后,资本的魔力迅速触动了教育行业每个人的神经,所有人都在寻找新的 ...
- 北大女生拿下阿里数学预赛第一名!决赛入围率不到1%,最小晋级选手只有14岁...
博雯 发自 凹非寺 量子位 报道 | 公众号 QbitAI 第三届阿里巴巴全球数学竞赛决赛名单现已公布. 经历了3天的预选赛,全球5万名选手中共有508人进入了决赛,晋级率不足1%. 本届预赛总分12 ...
- 留良乡稳健投资理财的四大原则
一.杰出的获利才干 关于稳健型出资者来说,理财产品的获利才干应该是他们最早考虑的问题.所以,在很多理财方法中,应挑选获利才干较高的理财产品,这样的话,能添加出资者成功的概率. 二.勿忘危险 危险与获利 ...
最新文章
- 信息系统项目管理师采购管理
- hdu 1272 小希的迷宫 (并查集)
- wxWidgets:wxTextCtrl类用法
- Coursera机器学习week11 单元测试
- 双层板在哪层覆铜_2020年中国印制电路板行业发展现状及发展趋势预测(图)...
- c语言程序算一元二次方程,以实例跟我学C语言:如何求解一元二次方程的根
- 注塑成型工艺流程四大知识点总结
- Process terminated
- 日语开发java自我介绍,用日语自我介绍,这些你一定会用到
- SQL的概述及DDL
- 鸿蒙app前后端流程实现
- R3300L Android相关的记录
- 二层交换与MAC地址
- 牛客网在线编程全部题目
- 日历签到html,简单的手机移动端日历签到js代码
- [转]最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现
- 【学习笔记】斯特林反演+单位根反演
- 基于Python的DELMIA二次开发(二):创建产品
- Bug 和什么最像?| 每日趣闻
- 【转载】国外软件外包项目网站(适用软件兼职)
热门文章
- 哈师大计算机学院2016级新生,【通知公告】哈尔滨师范大学2016—2017学年度国家励志奖学金获奖学生初审名单公示...
- npm install一直报错equest to https://registry.npm.taobao.org/underscore failed, reason: Client network
- OSI(open system internet)七层模型介绍以及NAT(Network Address Translation)技术详解
- Java多线程——什么是线程安全和线程不安全
- SpringCloud 基本使用
- 软件生命周期管理系统ALM配置说明(二)
- mysql时间戳里取小时
- 一文带你深入理解【Java基础】· 枚举类
- SQL-多表关联查询详解
- python怎么安装whl文件