标签:线段树
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4973
题意:有一段数字,长度n,数字为1~n,有两种操作,第一种是使区间[l,r]内的所有数字变成两个,长度n随之增大,第二种操作是查询区间[l,r]中相同的数字最多有多少个。
思路:比赛时扫了一眼,看区间要扩大,没有细想就觉得线段树做不了,而且当时没有人交这道题就没管了,然后看解题报告居然真的是线段树。。。觉得自己好傻逼。因为只有n种数字,n最大50000,线段树维护3个值:第i个数字有多少个(sum数组)、区间最多相同数字(maxm数组)、延迟更新标记(add数组),这道题只要想到维护第i个数字的个数,就好做多了,难的地方在于区间[l,r]不能像普通线段树那样了,得根据数字的个数确定区间,然后如果找到了当前区间在[l,r]范围内,则可以进行区间更新,否则应当进行单点更新。
这道题树状数组也可以做,要比线段树简洁的多。
#include<cstring> #include<string> #include<fstream> #include<iostream> #include<iomanip> #include<cstdio> #include<cctype> #include<algorithm> #include<queue> #include<map> #include<set> #include<vector> #include<stack> #include<ctime> #include<cstdlib> #include<functional> #include<cmath> using namespace std; #define PI acos(-1.0) #define MAXN 50100 #define eps 1e-7 #define INF 0x7FFFFFFF #define LLINF 0x7FFFFFFFFFFFFFFF #define seed 131 #define MOD 1000000007 #define ll long long #define ull unsigned ll #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 ll sum[MAXN<<2],maxm[MAXN<<2],add[MAXN<<2]; ll n,m; void pushup(ll rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; maxm[rt] = max(maxm[rt<<1],maxm[rt<<1|1]); } void pushdown(ll rt){ if(add[rt]>1){ sum[rt<<1] *= add[rt]; sum[rt<<1|1] *= add[rt]; maxm[rt<<1] *= add[rt]; maxm[rt<<1|1] *= add[rt]; add[rt<<1] *= add[rt]; add[rt<<1|1] *= add[rt]; add[rt] = 1; } } void build(ll l,ll r,ll rt){ add[rt] = 1; if(l==r){ sum[rt] = maxm[rt] = 1; return ; } ll m = (l+r)>>1; build(lson); build(rson); pushup(rt); } void update(ll x,ll L,ll R,ll l,ll r,ll rt){ if(L<=x&&x+sum[rt]-1<=R){ sum[rt] *= 2; maxm[rt] *= 2; add[rt] *= 2; return ; } if(l==r){ if(x<=L) sum[rt] += min(R,x+sum[rt]-1)-L+1; else sum[rt] += R-x+1; maxm[rt] = max(sum[rt],maxm[rt]); return ; } pushdown(rt); ll m = (l+r)>>1; ll p = x+sum[rt<<1]-1; if(L<=p) update(x,L,R,lson); if(p<R) update(p+1,L,R,rson); pushup(rt); } ll query(ll x,ll L,ll R,ll l,ll r,ll rt){ if(L<=x&&x+sum[rt]-1<=R){ return maxm[rt]; } if(l==r){ if(x<=L) return min(R,x+sum[rt]-1)-L+1; else return R-x+1; } pushdown(rt); ll res = 0; ll m = (l+r)>>1; ll p = x+sum[rt<<1]-1; if(L<=p) res = max(res,query(x,L,R,lson)); if(p<R) res = max(res,query(p+1,L,R,rson)); return res; } int main(){ ll t,i,j,l,r,k=1; char str[5]; scanf("%I64d",&t); while(t--){ scanf("%I64d%I64d",&n,&m); build(1,n,1); printf("Case #%I64d:\n",k++); while(m--){ scanf("%s%I64d%I64d",str,&l,&r); if(str[0]=='D') update(1,l,r,1,n,1); else printf("%I64d\n",query(1,l,r,1,n,1)); } } return 0; }
POJ--4973--A simple simulation problem.【线段树】
标签:线段树
原文地址:http://blog.csdn.net/zzzz40/article/details/38756539