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; }