题目链接 hdu5172
【题意】GTY有n个基友,出于某种恶趣味,GTY每天早上会让他的基友们排成一行,每个基友有一个特征值,表示基友有多雄壮或娘炮,你,作为GTY的助手,必须回答GTY的每个询问,GTY每次会问一个区间[l,r] 是否为一个1到r−l+1的排列。
【分析】这场BC是打得烂爆了,第一题忘记log的存在了然后就爆0了;回到这题,这题我现在只会线段树的做法,首先如果区间[l,r]要是一个1~r-l+1的排列的话就需要满足两个条件:
一:[l,r]的和为(1+r-l+1)*(1+r-l+1)/2;
二:使得[l,r]中每个数互相不重复;
第一个简单,前缀和搞定,对于第二个条件,用p[i]记录当前位置的数字在前一个最近的位置(需要加个w[j]记录每个数字j的最后一个位置),然后线段树求出每个区间[l,r]的最大的p[]就可以了,只要p<l(区间左下标)就说明区间[l,r]里面没有重复的数字。
【AC CODE】1419ms
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <map> //#include <unordered_map> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) #define id(x,y) (x+y|x!=y) const int INF = 0x3f3f3f3f, MAXN = 1000000+10; int w[MAXN],p[MAXN], mx[MAXN<<1]; LL sum[MAXN]; inline void push_up(int x, int y, int m) { mx[id(x,y)] = max(mx[id(x,m)],mx[id(m+1,y)]); } void bulid(int x, int y) { if(x == y) { mx[id(x,y)] = p[x]; return; } int m = (x+y)>>1; bulid(x,m); bulid(m+1,y); push_up(x,y,m); } int ql,qr; int query(int x, int y) { if(ql <= x && y <= qr) return mx[id(x,y)]; int m = (x+y)>>1; int ans = -1; if(ql <= m) ans = max(ans,query(x,m)); if(qr > m) ans = max(ans,query(m+1,y)); return ans; } int main() { #ifdef SHY freopen("e:\\1.txt", "r", stdin); #endif int n,m; sum[0] = 0; while(~scanf("%d %d%*c", &n, &m)) { clc(w,-1); int a; repe(i,1,n) { scanf("%d%*c", &a); sum[i] = sum[i-1]+a; p[i] = w[a]; w[a] = i; } bulid(1,n); rep(i,0,m) { scanf("%d %d%*c", &ql, &qr); LL num = qr-ql+1; if(sum[qr]-sum[ql-1] == (1+num)*num/2 && query(1,n) < ql) puts("YES"); else puts("NO"); } } return 0; }