2018黑龙江省赛 A Sequence Game 主席树+st表 / 主席树+线段树 / st表+莫队+离散化

7218: A Sequence Game

时间限制: 1 Sec  内存限制: 128 MB
提交: 128  解决: 32
[提交] [状态] [讨论版] [命题人:admin]

题目描述

One day, WNJXYK found a very hard problem on an Online Judge. This problem is so hard that he had been thinking about the solutions for a couple of days. And then he had a surprise that he misunderstood that problem and easily figured out a solution using segment tree. Now he still wonders that solution for the misread problem.
There is a sequence with N positive integers A1,A2,…,An and M queries. Each query will give you an interval [L,R] and require an answer with YES / NO indicates that whether the numbers in this interval are continuous in its integer range. 
Let us assume that the maximal number in an interval is mx and the minimal   number is mi. The numbers in this interval are continuous in its integer range means that each number from mi to mx appears at least once in this interval.

输入

The input starts with one line contains exactly one positive integer T which is the number of test cases. And then there are T cases follow.
The first line contains two positive integers n,m which has been explained above.
The second line contains n positive integers A1,A2,…,An.
Then there will be m lines followed. Each line contains to positive numbers Li,Ri indicating that the i th query’s interval is [Li,Ri].

输出

For each test case, output m line.
Each of following m lines contains a single string “YES”/ “NO” which is the answer you have got.

样例输入

2
3 3
3 1 2 
2 3
1 3
1 2
5 3
1 2 2 4 5 
1 5
1 3
3 3

样例输出

YES
YES
NO
NO
YES
YES

提示

T=5
1≤n≤100000
1≤Ai≤10^9
1≤m≤100000
The input file is very large, so you are recommend to use scanf() and printf() for IO.

来源/分类

2018黑龙江省赛 

这道题,比赛时写到头秃

一开始用主席树+st表,结果开大了MLE,开小了RE,几番试探没结果

然后换算法,另一个队友用莫队+st表写,我用主席树+线段树写,然后在比赛结束之前

我一直wa,找不到bug,她先wa再TLE,不知道怎么优化

然后,令人欣zhi喜xi的地方来了,比赛结束不久,她加了离散化就A了,我有个最小值初值赋错了,然后也A了

自闭

题意:给一个长度为n的序列,m次询问,每次求 [ l , r ] 内是否是连续的一串数,最大值到最小值之间的数最少出现一次

思路:解决的公式为 最大值 - 最小值 + 1 是否等于 不同数的个数 

           判断区间内不同数的个数,想到了主席树还有莫队,然后最大最小用st表,后来又想到再建一个线段树维护最大最小

我的代码:

#include <iostream>
#include <stdio.h>
#include <map>
#include <cstring>

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 1e5 + 7;
const int M = MAXN * 100;
const int inf=1e9+100;
int n, q, tot;
int a[MAXN];
int T[MAXN], lson[M], rson[M], c[M];
int maxx[MAXN << 2], minn[MAXN << 2];

void pushup(int rt)
{
    maxx[rt] = max(maxx[rt << 1], maxx[rt << 1 | 1]);
    minn[rt] = min(minn[rt << 1], minn[rt << 1 | 1]);
}

void build1(int l, int r, int rt)
{
    if (l == r)
    {
        maxx[rt] = a[l];
        minn[rt] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build1(l, mid, rt << 1);
    build1(mid + 1, r, rt << 1 | 1);
    pushup(rt);
}

int querymaxn(int L, int R, int l, int r, int rt)
{
    if (L <= l && R >= r) return maxx[rt];
    int mid = (l + r) >> 1;
    int ret = 0;
    if (L <= mid) ret = max(ret, querymaxn(L, R, l, mid, rt << 1));
    if (R > mid) ret = max(ret, querymaxn(L, R, mid + 1, r, rt << 1 | 1));
    return ret;
}

int queryminn(int L, int R, int l, int r, int rt)
{
    if (L <= l && R >= r) return minn[rt];
    int mid = (l + r) >> 1;
    int ret = 0x3f3f3f3f;
    if (L <= mid) ret = min(ret, queryminn(L, R, l, mid, rt << 1));
    if (R > mid) ret = min(ret, queryminn(L, R, mid + 1, r, rt << 1 | 1));
    return ret;
}

int build(int l, int r) {
    int root = tot++;
    c[root] = 0;
    if (l != r) {
        int mid = (l + r) >> 1;
        lson[root] = build(l, mid);
        rson[root] = build(mid + 1, r);
    }
    return root;
}

int update(int root, int pos, int val) {
    int newroot = tot++, tmp = newroot;
    c[newroot] = c[root] + val;
    int l = 1, r = n;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            lson[newroot] = tot++;
            rson[newroot] = rson[root];
            newroot = lson[newroot];
            root = lson[root];
            r = mid;
        } else {
            rson[newroot] = tot++;
            lson[newroot] = lson[root];
            newroot = rson[newroot];
            root = rson[root];
            l = mid + 1;
        }
        c[newroot] = c[root] + val;
    }
    return tmp;
}

int query(int root, int pos) {
    int ret = 0;
    int l = 1, r = n;
    while (pos < r) {
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            r = mid;
            root = lson[root];
        } else {
            ret += c[lson[root]];
            root = rson[root];
            l = mid + 1;
        }
    }
    return ret + c[root];
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        memset(maxx, 0, sizeof(maxx));
        memset(T, 0, sizeof(T));
        memset(lson, 0, sizeof(lson));
        memset(rson, 0, sizeof(rson));
        memset(c, 0, sizeof(c));
        for(int i=0; i<(MAXN<<2); i++){
            minn[i]=0x3f3f3f3f;
        }
        scanf("%d%d", &n, &q);
        tot = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        build1(1, n, 1);
        T[n + 1] = build(1, n);
        map<int, int> mp;
        for (int i = n; i >= 1; i--) {
            if (mp.find(a[i]) == mp.end()) {
                T[i] = update(T[i + 1], i, 1);
            } else {
                int tmp = update(T[i + 1], mp[a[i]], -1);
                T[i] = update(tmp, i, 1);
            }
            mp[a[i]] = i;
        }
        while (q--) {
            int l, r;
            scanf("%d%d", &l, &r);
            //cout << querymaxn(l, r, 1, n, 1) << endl;
            //cout << queryminn(l, r, 1, n, 1) << endl;
            if (querymaxn(l, r, 1, n, 1) - queryminn(l, r, 1, n, 1) + 1 == query(T[l], r)) puts("YES");
            else puts("NO");
        }
    }
    return 0;
}

队友莫队的代码:

#include <bits/stdc++.h>
const int N=1e5+10;
using namespace std;
typedef long long ll;
 
int n,m,block;
int lg2[N];
int a[N],b[N],dmax[N][35],dmin[N][35];
int cur=0,cnt[N];
struct node{
    int l,r,id;
}q[N];
bool ans[N];
 
bool cmp(node x,node y){
    return x.l/block==y.l/block?x.r<y.r:x.l/block<y.l/block;
}
template <class T>
inline void read(T &x){
    x=0;
    char c=getchar();
    T f=1;
    while(c<'0'||c>'9'){ if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ x=x*10+c-'0';c=getchar();}
    x*=f;
}
inline void log2(){
    lg2[0]=-1;
    for(int i=1;i<N;i++) lg2[i]=lg2[i>>1]+1;
}
void get_st(){
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i-1+(1<<j)<=n;i++){
            dmax[i][j]=max(dmax[i][j-1],dmax[i+(1<<(j-1))][j-1]);
            dmin[i][j]=min(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
        }
    }
}
inline int rmq(int l,int r,bool f){
    int k=lg2[r+1-l];
    if(f) return max(dmax[l][k],dmax[r+1-(1<<k)][k]);
    else return min(dmin[l][k],dmin[r+1-(1<<k)][k]);
}
inline void add(int x){
    if(++cnt[x]==1) cur++;
}
inline void del(int x){
    if(--cnt[x]==0) cur--;
}
 
int main()
{
    int t;read(t);
    log2();
    while(t--){
        read(n),read(m);
        block=sqrt(n);
        for(int i=1;i<=n;i++){
            read(a[i]);
            b[i]=a[i];
            dmax[i][0]=a[i];
            dmin[i][0]=a[i];
        }
        get_st();
        sort(b+1,b+1+n);
        int pos=unique(b+1,b+1+n)-(b+1);
        for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+pos,a[i])-b;
        for(int i=1;i<=m;i++){
            read(q[i].l),read(q[i].r);
            q[i].id=i;
        }
        sort(q+1,q+1+m,cmp);
        int l=1,r=0;
        cur=0;
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=m;i++){
            while(l<q[i].l) del(a[l++]);
            while(l>q[i].l) add(a[--l]);
            while(r<q[i].r) add(a[++r]);
            while(r>q[i].r) del(a[r--]);
            int maxx=rmq(l,r,1);
            int minx=rmq(l,r,0);
            if(maxx+1-minx==cur) ans[q[i].id]=1;
            else ans[q[i].id]=0;
        }
        for(int i=1;i<=m;i++){
            if(ans[i]) puts("YES");
            else puts("NO");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/renzijing/article/details/82389071