1. 程式人生 > >2018黑龍江省賽 A Sequence Game 主席樹+st表 / 主席樹+線段樹 / st表+莫隊+離散化

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;
}