您的位置:首页 > 其它

HDU 5172 GTY's gay friends 线段树+前缀和+全排列

2016-04-28 01:09 447 查看

题目链接:

hdu: http://acm.hdu.edu.cn/showproblem.php?pid=5172

bc(中文): http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=567&pid=1003

题解:

线段树+前缀和

一个区间要满足1到n的一个排列,要同时满足两点,一是它的和是n*(n+1)/2,这个可以用前缀和直接求;二是它每个元素不能重复。

区间内每个元素都不能重复:

  记录第i个元素的左边一个离他最近的值与他相等的数的位置,记在arr[i]里面,对于区间[L,r]要满足区间里面最大的arr[i](L<=i<=r)要小于L;这个可以用线段树或rmq维护。

要先比较第一个条件,即和要先等于n*(n+1)/2,满足了再去查线段树,否则会超时。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson (o<<1)
#define rson ((o<<1)+1)
#define M (l+(r-l)/2)
using namespace std;
typedef long long LL;

const int maxn = 1e6 + 10;
LL sumv[maxn << 2];
int maxv[maxn << 2];
int arr[maxn],vis[maxn];
int n, m;

int max(int a, int b) { return a > b ? a : b; }

void build(int o, int l, int r) {
if (l == r) {
maxv[o] = arr[l];
}
else {
build(lson, l, M);
build(rson, M + 1, r);
maxv[o] = max(maxv[lson], maxv[rson]);
}
}

int ql, qr;
void query(int o, int l, int r,int &ma) {
if (ql <= l&&r <= qr) {
ma = max(ma, maxv[o]);
}
else {
if (ql <= M) query(lson, l, M,ma);
if (qr > M) query(rson, M + 1, r, ma);
}
}

bool check(int l,int r) {
LL nn = r - l + 1;
if (nn*(nn + 1) / 2 != sumv[r] - sumv[l - 1]) return false;
int ma = -1;
query(1, 1, n,ma);
if (ma >= l) return false;
return true;
}

void init() {
sumv[0] = 0;
memset(vis, 0, sizeof(vis));
}

int main() {
while(scanf("%d%d", &n, &m) == 2 && n) {
init();
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
sumv[i] = sumv[i - 1] + x;
arr[i] = vis[x];
vis[x] = i;
}
build(1,1,n);
while (m--) {
scanf("%d%d", &ql, &qr);
LL len = qr - ql + 1;
if (check(ql,qr)) {
puts("YES");
}
else {
puts("NO");
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: