hdu 4973 A simple simulation problem.(线段树)
来源:互联网 发布:大数据研究所 编辑:程序博客网 时间:2024/06/06 04:08
http://acm.hdu.edu.cn/showproblem.php?pid=4973
有两种操作
D l r 将【l,r】区间翻倍
Q l r询问[l,r]中相同数字出现的最多次数
比赛的时候脑子太乱了,没有想到怎么做。发现每次翻倍序列的长度都在变化,区间对应的数也在变,没有思路。
但是静下心来想一想,思路还是挺清晰的。
无论怎么翻倍,序列中的数都是连续的,范围是1~n。可以拿一个数组来记录每个数出现的次数,当更新或询问区间[l,r]时,可以利用其前缀和找到区间[l,r]对应的数字分别是lx,rx,对于lx+1,rx-1内的数字是完全翻倍的,可以用线段树维护区间的和相同数字的最大数目,由于l,r并不一定完全包含在lx.rx内,端点需要特殊处理。
那么重点就是怎样找到l,r对应的数更新区间[lx,rx],可以把每个数字所在区间的左端点作为连接l,r和lx,rx的纽带。这里想了许久才绕过来。
WA了几次,分别是:因为多次翻倍,输入的区间端点可能超int,要用__int64;push_dow的时候lazy标记要累加左右儿子,而不是直接赋值(经常犯nc的错误);query的时候忘记push_down(这个貌似更nc)
#include <stdio.h>#include <iostream>#include <map>#include <set>#include <list>#include <stack>#include <vector>#include <math.h>#include <string.h>#include <queue>#include <string>#include <stdlib.h>#include <algorithm>#define LL __int64#define eps 1e-12#define PI acos(-1.0)using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 50010;struct node{ int l,r; int lazy; //记录区间翻倍次数 LL sum;//区间的和 LL mx;//区间内相同数字出现的最多次数}tree[maxn*4];void push_up(int v){ tree[v].mx = max(tree[v*2].mx,tree[v*2+1].mx); tree[v].sum = tree[v*2].sum + tree[v*2+1].sum; return;}void push_down(int v){ if(tree[v].l == tree[v].r || tree[v].lazy == 0) return; tree[v*2].lazy += tree[v].lazy;//累加,累加 tree[v*2+1].lazy += tree[v].lazy; tree[v*2].mx <<= (LL)tree[v].lazy; tree[v*2].sum <<= (LL)tree[v].lazy; tree[v*2+1].mx <<= (LL)tree[v].lazy; tree[v*2+1].sum <<= (LL)tree[v].lazy; tree[v].lazy = 0;}void build(int v, int l, int r){ tree[v].l = l; tree[v].r = r; tree[v].lazy = 0; if(l == r) { tree[v].sum = (LL)1; tree[v].mx = (LL)1; return; } int mid = (l+r)>>1; build(v*2,l,mid); build(v*2+1,mid+1,r); push_up(v);}void update(int v, LL st, LL l, LL r)//st是该节点的左端点在序列中的下标,那么可知这个节点所在区间是[st,st+tree[v].sum-1]。{ if(st == l && st+tree[v].sum-1 == r) { tree[v].lazy++; tree[v].mx <<= (LL)1; tree[v].sum <<= (LL)1; return; } if(tree[v].l == tree[v].r) //针对左右端点lx,rx,它们不全在区间[l,r]内,只更新其部分 { tree[v].sum += (LL)(r-l+1); tree[v].mx = tree[v].sum; return; } push_down(v); LL m = st + tree[v*2].sum - 1; if(r <= m) update(v*2,st,l,r); else if(l > m) { update(v*2+1,m+1,l,r); } else { update(v*2,st,l,m); update(v*2+1,m+1,m+1,r); } push_up(v);}LL query(int v, LL st, LL l, LL r){ if(st == l && st+tree[v].sum-1 == r) return tree[v].mx; if(tree[v].l == tree[v].r) return r-l+1; push_down(v); LL m = st+tree[v*2].sum-1; if(r <= m) return query(v*2,st,l,r); else if(l > m) return query(v*2+1,m+1,l,r); else return max(query(v*2,st,l,m),query(v*2+1,m+1,m+1,r));}int main(){ int test; int n,m; LL l,r; char ch[4]; scanf("%d",&test); for(int item = 1; item <= test; item++) { scanf("%d %d",&n,&m); build(1,1,n); printf("Case #%d:\n",item); while(m--) { scanf("%s %I64d %I64d",ch,&l,&r); if(ch[0] == 'D') update(1,1,l,r) else printf("%I64d\n",query(1,1,l,r)); } } return 0;}
1 0
- hdu 4973 A simple simulation problem(线段树)
- HDU 4973 A simple simulation problem. 线段树
- 【HDU】4973 A simple simulation problem. 线段树
- HDU 4973 A simple simulation problem.(线段树)
- hdu 4973 A simple simulation problem.(线段树)
- HDU 4973 A simple simulation problem.(线段树)
- HDU-4973-A simple simulation problem.(线段树)
- HDU 4973 A simple simulation problem.(线段树)
- hdu 4973 A simple simulation problem 线段树
- hdu 4973 A simple simulation problem.---线段树
- HDU 4973 A simple simulation problem. 线段树
- hdu4973 A simple simulation problem. 线段树
- HDU4973:A simple simulation problem.(线段树)
- 【线段树】 HDOJ 4973 A simple simulation problem.
- POJ--4973--A simple simulation problem.【线段树】
- hdu 4973 A simple simulation problem 线段树 2014 Multi-University Training Contest 10-1003
- hdu 4973 A simple simulation problem (多校第10场 线段树)
- hdu - 4973 - A simple simulation problem.(线段树单点更新 + 区间更新)
- CentOS下Hadoop伪分布模式安装
- 策略模式
- 莫名其妙的解决了一个莫名其妙的问题
- HDUOJ--4888--Redraw Beautiful Drawings【isap】网络流+判环
- ubuntu安装vncserver实现图形化访问
- hdu 4973 A simple simulation problem.(线段树)
- Java Class-类-对象 类加载器
- Head-of-line blocking
- 评论
- demo
- JPA的本地查询(native query)
- java集合
- 虚函数
- Algorithm Topic 算法分类