标签:hdu5172 gtys gay friends 线段树单点更新 bestcoder#29
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5172
题意:给出n个数,m个询问,问你[l,r]区间内是否为1到r-l+1的全排列。 大小很容易我们通过记录前缀和很容易求出来,但是关键是去重。 考虑线段树做法,我们记录每个点的靠左最近的相同元素的位置,然后求 整个区间的最大值(即最大的前驱)如果小于l,即满足条件,输出YES。
好吧,其实这个题目我是搜的RMQ算法出来的,因为我想练一下RMQ算法,所以我就看了一下别人的博客,自己也写了一下,结果死活MLE。。。
好吧,我仔细看了一下,1000000的数据量用RMQ开一个二维数组1000000*20,显然会超内存。。。
结果我不得不老老实实的滚回去用线段树写了。。。orz....
RMQ的MLE代码:
#include<iostream> #include<string> #include<cstdio> #include<cstring> #include<queue> #include<map> #include<cmath> #include<stack> #include<set> #include<vector> #include<algorithm> #define LL long long #define inf 1<<30 #define sf(a) scanf("%d",&a); #define CLEAR(a,b) memset(a,b,sizeof(a)) using namespace std; /* TLE...显然超内存; */ const int N=1000005; int n,m,a,b; int num[N],pre[N]; int dp[N][21]; int sum[N]; void ST(int len) { for(int i=1;i<=n;i++) dp[i][0]=num[i]; for(int j=1;1<<j < n;j++){ for(int i=1;i+(1<<j)-1<n;i++){ dp[i][j]=max(dp[i][j-1],dp[i+1<<(j-1)][j-1]); } } } int rmq(int s,int v) { int k=(int)(log(v-s+1)*1.0/log(2.0)); return max(dp[s][k],dp[v-1<<k+1][k]); } int main() { while(~scanf("%d%d",&n,&m)){ CLEAR(pre,0); CLEAR(sum,0); for(int i=1;i<=n;i++){ sf(a); sum[i]+=sum[i-1]+a; num[i]=pre[a]; pre[a]=i; } ST(n); while(m--){ sf(a);sf(b); double tmp=(b-a+2)*(b-a+1)*1.0/2.0; if(tmp!=sum[b]-sum[a-1]){ //cout<<tmp<<' '<<sum[b]-sum[a-1]<<' '; printf("NO\n"); continue; }else{ if(rmq(a,b)<a) printf("YES\n"); else printf("NO\n"); } } } return 0; }
线段树AC代码:
#include<iostream> #include<string> #include<cstdio> #include<cstring> #include<queue> #include<map> #include<cmath> #include<stack> #include<set> #include<vector> #include<algorithm> #define LL long long #define inf 1<<30 #define s(a) scanf("%d",&a) #define CLEAR(a,b) memset(a,b,sizeof(a)) using namespace std; const int N=1000005; int n,m,a,b; int pre[N],sum[N]; // sum存总和,pre定位该数字上一次出现的位置; struct node { int l,r; int pre; // 用线段树维护最近一个重复的数字; }node[N<<2]; void PushUp(int rt) { node[rt].pre=max(node[rt<<1].pre,node[rt<<1|1].pre); } void build(int l,int r,int rt) { node[rt].l=l; node[rt].r=r; node[rt].pre=0; if(l!=r){ int mid=(l+r)>>1; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); } } void Insert(int v,int p,int rt) { int ll=node[rt].l,rr=node[rt].r; if(ll==rr&&p==ll){ node[rt].pre=pre[v]; return; } int mid=(ll+rr)>>1; if(p<=mid) Insert(v,p,rt<<1); else Insert(v,p,rt<<1|1); PushUp(rt); } int query(int l,int r,int rt) { int ll=node[rt].l,rr=node[rt].r; if(ll==l&&rr==r){ return node[rt].pre; } int mid=(ll+rr)>>1; if(r<=mid) return query(l,r,rt<<1); else if(l>mid) return query(l,r,rt<<1|1); else return max(query(l,mid,rt<<1),query(mid+1,r,rt<<1|1)); } int main() { while(~s(n)){ s(m); CLEAR(pre,0); CLEAR(sum,0); build(1,n,1); for(int i=1;i<=n;i++){ s(a); sum[i]+=sum[i-1]+a; Insert(a,i,1); pre[a]=i; } while(m--){ s(a);s(b); int tmp=(b-a+2)*(b-a+1)*1.0/2.0; // 如果是全排列那么最后的和必然符合这个公式; if(sum[b]-sum[a-1]!=tmp){ printf("NO\n"); continue; }else{ if(query(a,b,1)<a) printf("YES\n"); // 查询该区间最近一个重复的数字出现的位置,如果比a小,那就说明这个区间没有出现过重复的数字; else printf("NO\n"); } } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU-5172-GTY's gay friends-线段树单点更新
标签:hdu5172 gtys gay friends 线段树单点更新 bestcoder#29
原文地址:http://blog.csdn.net/wlxsq/article/details/47281165