Vijos 3091 长跑
来源:互联网 发布:windows程序设计最新版 编辑:程序博客网 时间:2024/04/28 15:49
【问题描述】
小沐近段时间非常能吃,身体日渐胖了起来。他父亲担心他会长的过于肥胖,要求他每天坚持长跑锻炼。
父亲为他设计了一条长跑路线,依次有n个必经点,必经点表示为平面上的坐标(x,y),相邻两个必经点的(x1,y1)和(x2,y2)距离表示为|x1-x2 | + |y1-y2 |。同时,为了让跑步不那么单调,父亲还会时常改变其中的某些必经点的位置。 每一次长跑会,父亲会为小沐指定一条长跑路线的子路线,一条子路线是整条路线中包含若干连续必经点的一段,同时允许他可以省略其中的一个必经点(即直接绕过这个点到下一个点),但是省略的必经点不能是子路线的起点和终点。
那么问题来了,小沐想知道每次跑步的最短距离是多少。
【输入格式】
输入的第1行包含两个整数:n和q,表示长跑路线有n个必经点,q次对路线的操作。接下来n行,每行2个整数,表示一个必经点的坐标,坐标范围在[-1000,1000]。再接下来q行,每行一个命令,格式有2种:
U i x y: 表示把第i个必经点的坐标改为(x, y)。
Q i j: 表示从父亲指定的子路线是必经点i到j的子路线,你需要回答小沐在该子路线上跑步的最短长度(可以省略一个必经点)。
【输出格式】
对每个Q命令,输出一个整数,表示子路线的最短长度。
【输入样例】
5 5
-4 4
-5 -3
-1 5
-3 4
0 5
Q 1 5
U 4 0 1
U 4 -1 1
Q 2 4
Q 1 4
【输出样例】
11
8
8
【数据范围】
对于20%的数据满足:1 ≤ n,q ≤ 100
对于50%的数据满足:1 ≤ n,q ≤ 1000
对于100%的数据满足:1 ≤ n,q ≤ 100000
线段树…….这次是真的用来维护线段了。
其实二维平面没什么意义,我们完全可以把所有的必经点看做是一些一维数轴上的点,只不过点距需要用公式来特殊处理(曼哈顿距离),这样一转换,本题的方向就变得很明确了——就是单点修改+区间查询,妥妥的线段树。
某个点要变一下位置,带来的是点距的改变,我们用一个数组A[ ]来存储这些点距,其中A[i]表示必经点i到必经点i+1的距离,于是用A[1]….A[N-1]就把相邻点的点距存下来了。接下来就是用线段树来维护数组A[ ]了。
查询并不是那么常规,因为根据题目条件,我们在走一段必经点时(比如i->j),我们是可以忽略一个点的,那到底忽略哪个点能使距离最小呢?仿照上述思路,将忽略一个点后减小的距离同样地用一个数组B[ ]来存储,这样我们又可以拿线段树来维护了。
本题比较特殊的也是这一点,并不是直接拿线段树维护必经点的下标,而是维护距离,但直接维护距离显然是不可行的,所以我们拿数组来存储这些距离,再用线段树维护数组的下标。
可以说是很巧妙的一个技巧了。
另:初始化线段树、更新节点时,可能会访问到不符合要求的点,其实没什么关系,因为查询的时候我们并不会访问到这些点。
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define ll long longusing namespace std;const int maxn=100000+5; const int inf =1e8;int n,q,rt,np;int a[maxn],b[maxn],lc[maxn*2],rc[maxn*2],maxv[maxn*2],sum[maxn*2];char op[1];struct data{int x;int y;}v[maxn];int calc1(int i,int j){return abs(v[i].x-v[j].x)+abs(v[i].y-v[j].y);}int calc2(int i){if(i==1 || i==n) return 0;return calc1(i-1,i)+calc1(i,i+1)-calc1(i-1,i+1);}void pushup(int now){sum[now]=sum[lc[now]]+sum[rc[now]];maxv[now]=max(maxv[lc[now]],maxv[rc[now]]);return;}void build(int &now,int l,int r){now=++np;if(l==r){sum[now]=calc1(l,l+1); maxv[now]=calc2(l);return;}int m=(l+r)>>1;build(lc[now],l,m);build(rc[now],m+1,r);pushup(now);return;}void update(int now,int l,int r,int i,int k){if(l==i && r==i){if(k==1) sum[now]=calc1(i,i+1);if(k==2)maxv[now]=calc2(i);return;}int m=(l+r)>>1;if(i<=m)update(lc[now],l,m,i,k);else if(i>m)update(rc[now],m+1,r,i,k);pushup(now);return;}int query(int now,int l,int r,int i,int j,int k){if(i<=l && r<=j){if(k==1)return sum[now];if(k==2)return maxv[now];}int m=(l+r)>>1;if(j<=m)return query(lc[now],l,m,i,j,k);else if(i>m)return query(rc[now],m+1,r,i,j,k);else{int tl=query(lc[now],l,m,i,m,k);int tr=query(rc[now],m+1,r,m+1,j,k);if(k==1)return tl+tr;if(k==2) return max(tl,tr);}}void init(){scanf("%d%d",&n,&q);for(int i=1;i<=n;i++)scanf("%d%d",&v[i].x,&v[i].y);memset(lc,0,sizeof(lc));memset(rc,0,sizeof(rc));memset(sum,0,sizeof(sum));memset(maxv,0,sizeof(maxv));rt=np=0;build(rt,1,n);return;}void solve(){ int i,j,x,y; for(int k=1;k<=q;k++) { scanf("%s",op); if(op[0]=='U') { scanf("%d%d%d",&i,&x,&y); v[i]=(data){x,y}; update(rt,1,n,i,1); if(i!=1)update(rt,1,n,i-1,1); update(rt,1,n,i,2); if(i!=n) update(rt,1,n,i+1,2); if(i!=1) update(rt,1,n,i-1,2); } else if(op[0]=='Q') { scanf("%d%d",&i,&j); int ans; if(i!=j) ans=query(rt,1,n,i,j-1,1); else ans=0; if(j-i>1) ans=ans-query(rt,1,n,i+1,j-1,2);cout<<ans<<"\n"; } } return;}int main(){//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);init();solve();return 0;}
- Vijos 3091 长跑
- 长跑
- 长跑
- 结束长跑
- 在工作中长跑
- bzoj2959: 长跑
- BZOJ2959: 长跑
- 【bzoj2959】长跑
- 跳高和长跑
- 人生就是长跑
- 生活是长跑
- 人生如长跑
- NYOJ 631 冬季长跑
- WinterCamp 2013 长跑
- bzoj 2959: 长跑 lct
- 2959: 长跑 LCT+dfs
- BZOJ2959——长跑
- BZOJ 2959 长跑
- Warning: Failed prop type: Invalid prop `enablesReturnKeyAutomatically` of type `string` supplie
- 浏览器内核
- pdo如何防止 sql注入
- Java消息中间件学习笔记八 -- ActiveMQ集群
- C练习
- Vijos 3091 长跑
- 深度学习-正则化
- mongo基本查询
- ZOJ 3993 Safest Buildings
- Vue axios中this的指向问题
- 数据结构实验之二叉树八:(中序后序)求二叉树的深度
- FTP 425 Cannot open data connection.
- 暴力破解FTP服务器用户名密码
- 如何在Windows下安装Linux子系统(Ubuntu,openSUSU,SUSU Linux Server)