codeforces765F Souvenirs

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

题目链接:http://codeforces.com/contest/765/problem/F

正解:线段树

解题报告:

  我看完这道题,只想到了莫队套平衡树套堆的带$log$根号算法(和暴力有啥区别)…

  考虑把询问按右端点排序,那么我可以从左往右把端点一个一个往里面加,并一边查询。

  我维护一个$f[i]$表示以i为左端点的答案,那么我每次加入一个新的点时,相当于是需要更新左边的所有的$f$。

  我们用线段树支持查询操作,线段树上每个节点维护所控制区间的有序序列,以及这个区间内部的最优$ans$。

  我们考虑如何优化加入点时,更新操作的复杂度。

  因为$f$一定是从左往右递增的,而查询操作是按右端点升序的。

  我每次更新时先更新右边再更新左边,顺便维护一个当前最优值。

  我每次进入一个线段树上的节点更新时,我先在其有序序列查询一下,比新加入的点大的第一个值和小的第一个值,如果新加入点$val+$当前最优值$<=$大的,并且,新加入点$val-$最优值$>=$小的,说明这个区间不可能比当前最优值更优。

  那我就没有必要更新下去了,因为我的最优值是在右边取到的,而不难想到,我先做右边再坐左边,那么以后每次查询一定都会覆盖右边取到最优值的那个区间,所以这个节点无论如何不可能是最优值,所以没必要往下更新下去了。

  可以想一想这样做的复杂度稳定在$log$级别,总复杂度$O(nlog^2n)$。

  

//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
using namespace std;
#define lc root<<1
#define rc root<<1|1
typedef long long LL;
typedef complex<double> C;
const double pi = acos(-1);
const int MAXN = 100011;
const int inf = (1<<30)-1;//不要炸int了...
int n,m,val[MAXN];
int A[MAXN*3];
struct node{//线段树每个节点保存的这个区间的有序序列
	vector<int>w;
	int ans;//ans保存的是以区间内每个数为左端点,右端点不断后移的最小值
}a[MAXN*3];

struct ask{
	int l,r,id;
}q[MAXN*3];

inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<‘0‘||c>‘9‘) && c!=‘-‘) c=getchar();
    if(c==‘-‘) q=1,c=getchar(); while (c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar(); return q?-w:w;
}

inline void upd(int &x,int y){ if(y<x) x=y; }

inline bool cmp(ask q,ask qq){ return q.r<qq.r; }

inline void build(int root,int l,int r){
	if(l==r) { a[root].w.push_back(val[l]); a[root].ans=inf;/*需要设为inf!!!*/ return ; }
	int mid=(l+r)>>1; build(lc,l,mid); build(rc,mid+1,r);
	int head=0,s1=a[lc].w.size(),s2=a[rc].w.size();
	for(int i=0;i<s1;i++) {//归并
		while(head<s2 && a[rc].w[head]<=a[lc].w[i]) a[root].w.push_back(a[rc].w[head]),head++;
		a[root].w.push_back(a[lc].w[i]);
	}
	while(head<s2) a[root].w.push_back(a[rc].w[head]),head++;
	a[root].ans=min(a[lc].ans,a[rc].ans);
	for(int i=1;i<=r-l;i++) upd(a[root].ans,a[root].w[i]-a[root].w[i-1]);
}

inline int query(int root,int l,int r,int ql,int qr){
	if(ql<=l && r<=qr) return a[root].ans; int mid=(l+r)>>1;
	if(ql>mid) return query(rc,mid+1,r,ql,qr);
	else if(qr<=mid) return query(lc,l,mid,ql,qr);
	else return min(query(lc,l,mid,ql,qr),query(rc,mid+1,r,ql,qr));
}

//由于右端点往右移动过程中,以之前的点为左端点的ans不升,而原先保存的仅是控制区间内的最小ans,需要用新加入的节点去更新
inline void modify(int root,int l,int r,int pos,int vv,int &nowans){
	if(l==r) { upd(nowans,abs(a[root].w[0]-vv)/*!!!*/); upd(a[root].ans,nowans); return ; }
	vector <int> :: iterator it = lower_bound(a[root].w.begin(),a[root].w.end(),vv);
	if((it==a[root].w.end() || *it>=vv+nowans) && (it==a[root].w.begin() || *(it-1)<=vv-nowans)) {
		upd(nowans,query(root,l,r,l,pos));
		return ;
	}
	int mid=(l+r)>>1;
	if(pos>mid) modify(rc,mid+1,r,pos,vv,nowans),modify(lc,l,mid,pos,vv,nowans);//左边也需要更新,不过先更新右边!因为ans单增!
	else modify(lc,l,mid,pos,vv,nowans);
	a[root].ans=min(a[root].ans,min(a[lc].ans,a[rc].ans));//记得update,不要丢失了本来的最优值!有可能未下传或者不更优!
}

inline void work(){
	n=getint(); for(int i=1;i<=n;i++) val[i]=getint();
	build(1,1,n); m=getint(); for(int i=1;i<=m;i++) q[i].l=getint(),q[i].r=getint(),q[i].id=i;
	sort(q+1,q+m+1,cmp); int now=1,minl;
	for(int o=1;o<=m;o++) {
		while(now<q[o].r)
			minl=inf,modify(1,1,n,now,val[now+1]/*!!!*/,minl),now++;//注意不要用自己更新了自己!
		A[q[o].id]=query(1,1,n,q[o].l,q[o].r);
	}
	for(int i=1;i<=m;i++) printf("%d\n",A[i]);
}

int main()
{
    work();
    return 0;
}

  

时间: 2024-08-08 08:41:54

codeforces765F Souvenirs的相关文章

hdoj 2126 Buy the souvenirs 【另类01背包】

题意:求最多购买的件数以及有几种方法. 一看到这题就想到了背包,因为求得是种类数,所以我们可以将件数看做价值,将价格看做重量,这就变成01背包了(dp),但是还要求有几种购买方案,那么再来一个背包(kind). 分析:有三种情况: 1>dp[j] < dp[j-s[i]]+1 那么对于这一种情况  方案背包的状态转移方程是kind[j] = kind[j-s[i]]?kind[j-s[i]]:1;(考虑到kind[j-s[i]] ==0的时候,这时候kind[j] = 1): 证明:为什么是k

Buy the souvenirs (01背包,动归)

When the winter holiday comes, a lot of people will have a trip. Generally, there are a lot of souvenirs to sell, and sometimes the travelers will buy some ones with pleasure. Not only can they give the souvenirs to their friends and families as gift

hdu2126---Buy the souvenirs(01背包方案数)

Problem Description When the winter holiday comes, a lot of people will have a trip. Generally, there are a lot of souvenirs to sell, and sometimes the travelers will buy some ones with pleasure. Not only can they give the souvenirs to their friends

(01背包)HDU - 2126 Buy the souvenirs

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126 题意:给n个物品,和m块钱,输出最多物品个数和其方案数. 委屈:求出最多物品个数就是一个裸的01背包,但是同时求出方案数,难住了我. 想了半天,感觉可以一波dp求出来,但是又想不明白状态是怎么表示和转移的. 无奈就先写个dfs提交试一发,果断超时了. 最后无奈看了题解,只能说,01背包还是不会. 其实与其说01背包不会不如说动态规划不会,感觉好难. 感觉自己好lowbee啊.. 感觉碰到dp就

[HDU 2126] Buy the souvenirs (动态规划)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126 题意:给你n个物品,m元钱,问你最多能买个多少物品,并且有多少种解决方案. 一开始想到的是,先解决给m元钱因为我花的钱少就一定能购买够多的物品,因此是个贪心算法. 记买最多的物品数为c. 然后就是设计状态dp[i][j]代表我从前i个物品里花了j元钱,买c个物品有多少种方案. 后来发现状态维数不够,得重新想想. 于是就想到: 设计状态dp[i][j][k]代表我从前i个物品里买了j个,花的钱不

hdu 2126 Buy the souvenirs(记录总方案数的01背包)

Buy the souvenirs Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1662    Accepted Submission(s): 611 Problem Description When the winter holiday comes, a lot of people will have a trip. Genera

hdu2126 Buy the souvenirs

Problem Description When the winter holiday comes, a lot of people will have a trip. Generally, there are a lot of souvenirs to sell, and sometimes the travelers will buy some ones with pleasure. Not only can they give the souvenirs to their friends

HDU 2126 Buy the souvenirs

Buy the souvenirs Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 212664-bit integer IO format: %I64d      Java class name: Main When the winter holiday comes, a lot of people will have a trip. Generally, the

HDU2126——背包DP(开状态)——Buy the souvenirs

Description When the winter holiday comes, a lot of people will have a trip. Generally, there are a lot of souvenirs to sell, and sometimes the travelers will buy some ones with pleasure. Not only can they give the souvenirs to their friends and fami