數據結構與第k大

HDU2665
題意:給你一個數列長爲n,(1<=n<=100000),q次詢問,(1<=q<=100000)
題解:高級數據結構
hdu2665
+ 嘗試一
數列分塊(求小於某個數的個數),再加二分得到答案。
結果(TLE),時間複雜度(O(qnlog2(n)log2(num)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;

ll read()
{
    ll x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

const int maxn=50005;
int n,block;
int v[maxn],bl[maxn],atag[maxn];
vector<int >ve[maxn];
void add(int a,int b,int c)
{
    for(int i=a; i<=min(b,block*bl[a]); i++)
    {
        v[i]+=c;
    }
    if(bl[a]!=bl[b])
    {
        for(int i=bl[b]*(block-1)+1; i<=b; i++)
        {
            v[i]+=c;
        }
    }
    for(int i=bl[a]+1; i<=bl[b]-1; i++)
    {
        atag[i]+=c;
    }
}
int query(int a,int b,int x)
{
    int ans=0;
    for(int i=1; i<=min(bl[a]*block,b); i++)
    {
        if(v[i]+atag[bl[a]]<x)
        {
            ans++;
        }
    }
    if(bl[a]!=bl[b])
        for(int i=block*(bl[b]-1)+1; i<=b; i++)
        {
            if(v[i]+atag[bl[b]]<x)
                ans++;
        }
    for(int i=bl[a]+1; i<=bl[b]-1; i++)
    {
        x-=atag[i];
        ans+=lower_bound(ve[i].begin(),ve[i].end(),x)-ve[i].begin();
    }
    return ans;
}
int main()
{

    int f,a,b,c,k,q;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i=0;i<1000;i++)ve[i].clear();
        n=read();
        q=read();
        block=sqrt(n);
        mem(atag,0);
        for(int i=1; i<=n; i++)
        {
            v[i]=read();
            bl[i]=(i-1)/block+1;
        }
        for(int i=1; i<=n; i++)
        {
            ve[bl[i]].push_back(v[i]);
        }
        for(int i=1; i<=bl[n]; i++)
        {
            sort(ve[i].begin(),ve[i].end());
        }
        for(int i=1; i<=q; i++)
        {

            a=read();
            b=read();
            k=read();
            int l=1,r=1e5;
            while(l<=r)
            {
                int m=(l+r)/2;
                if(query(a,b,m)<=(k-1))
                    l=m+1;
                else
                    r=m-1;
            }
            printf("%d\n",r);

        }
    }

    return 0;
}
  • 嘗試二
    貼一個單次樹狀數組求第k大代碼;(感覺還不如快排>_<)
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int bit[maxn],v[maxn];
int n,m,q;
vector<int>hash;
int lowbit(int x)
{
    return x&(-x);
}
void add(int x)
{
    for(int i=x; i<=m; i+=lowbit(i))
    {
        bit[i]+=1;
    }
}
int ask(int x)
{
    int sum=0;
    for(int i=x; i>0; i-=lowbit(i))
    {
        //  cout<<"??"<<' '<<i<<endl;
        sum+=bit[i];
    }
    return sum;
}
int main()
{
    int k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        hash.clear();
        memset(bit,0,sizeof bit);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&v[i]);
            hash.push_back(v[i]);
        }
        sort(hash.begin(),hash.end());
        hash.erase(unique(hash.begin(),hash.end()),hash.end());
        m=hash.size();
        for(int i=1; i<=n; i++)
        {
            int d=lower_bound(hash.begin(),hash.end(),v[i])-hash.begin();
            add(d+1);
        }
        int l=1,r=m;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(ask(mid)<=k)
                l=mid+1;
            else
                r=mid-1;
        }
        if(ask(r)<k)r++;
        printf("%d\n",hash[r-1]);
    }

    return 0;
}
  • 嘗試三
    堆排,用一個堆存前k大的k個元素,最後pop();
  • 嘗試四
    模擬快排->
    單次查詢複雜度接近O(n) 但是區間動態後O(nq) ,無力求解

非TLE的解法看下面
+ 嘗試一
主席樹:將數列的每個前綴建一棵線段樹,技巧通過觀察可以發現第i顆樹和第i+1顆樹只有一條鏈不同,所以可以在原來的基礎上建樹(避免MLE);樹的葉子節點存的是小於當前節點下標的值的個數。所以求區間[l,r] 既是求T[r]T[l1]
貼一個學習主席樹的博客->

#include<bits/stdc++.h>
#define lson l,m
#define rson m+1,r
using namespace std;

const int maxn=100005;

struct Node{
    int l,r,sum;
}p[maxn<<5];//畢竟有100000顆線段樹。

int T[maxn],a[maxn],Hash[maxn],cnt=0;

int build(int l,int r)
{
    int rt=(++cnt);
    if(l==r)
    {
        return p[rt].sum=0;
    }
    int m=(l+r)>>1;
    p[rt].l=build(lson);//注意這裏的左右子樹不在通過計算得到
    p[rt].r=build(rson);//因爲多棵線段樹的左右節點摻雜,不存在原來線段樹的計算規律。
    return rt;
}
int update(int pre,int l,int r,int x)
{
    int rt=(++cnt);//rt爲新加的一條樹鏈的節點
    p[rt].sum=p[pre].sum+1;
    p[rt].l=p[pre].l;
    p[rt].r=p[pre].r;
    if(l==r)return rt;
    int m=(l+r)>>1;
    if(x<=m)p[rt].l=update(p[pre].l,lson,x);
    else p[rt].r=update(p[pre].r,rson,x);
    return rt;
}
int query(int u,int v,int l,int r,int k)
{
    if(l==r)
    {
        return l;
    }
    int m=(l+r)>>1;
    int num=p[p[v].l].sum-p[p[u].l].sum;
    if(num>=k)return query(p[u].l,p[v].l,lson,k);
    else return query(p[u].r,p[v].r,rson,k-num);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        cnt=0;
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            Hash[i]=a[i];
        }
        sort(Hash+1,Hash+1+n);
        int d=unique(Hash+1,Hash+n+1)-Hash-1;
        T[0]=build(1,d);
        for(int i=1;i<=n;i++)
        {
            int x=lower_bound(Hash+1,Hash+d+1,a[i])-Hash;
            T[i]=update(T[i-1],1,d,x);
        }
        while(m--)
        {
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            int x=query(T[l-1],T[r],1,d,k);
            printf("%d\n",Hash[x]);
        }
    }
    return 0;
}
//大佬的不用結構體的模板
#include<bits/stdc++.h>
#define lson l, m
#define rson m+1, r
using namespace std;
const int N=1e5+5;
int L[N<<5], R[N<<5], sum[N<<5];
int tot;
int a[N], T[N], Hash[N];
int build(int l, int r)
{
    int rt=(++tot);
    sum[rt]=0;
    if(l<r)
    {
        int m=(l+r)>>1;
        L[rt]=build(lson);
        R[rt]=build(rson);
    }
    return rt;
}

int update(int pre, int l, int r, int x)
{
    int rt=(++tot);
    L[rt]=L[pre], R[rt]=R[pre], sum[rt]=sum[pre]+1;
    if(l<r)
    {
        int m=(l+r)>>1;
        if(x<=m)
            L[rt]=update(L[pre], lson, x);
        else
            R[rt]=update(R[pre], rson, x);
    }
    return rt;
}

int query(int u, int v, int l, int r, int k)
{
    if(l>=r)
        return l;
    int m=(l+r)>>1;
    int num=sum[L[v]]-sum[L[u]];
    if(num>=k)
        return query(L[u], L[v], lson, k);
    else
        return query(R[u], R[v], rson, k-num);
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        tot=0;
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d", &a[i]);
            Hash[i]=a[i];
        }
        sort(Hash+1, Hash+n+1);
        int d=unique(Hash+1, Hash+n+1)-Hash-1;
        T[0]=build(1, d);
        for(int i=1; i<=n; i++)
        {
            int x=lower_bound(Hash+1, Hash+d+1, a[i])-Hash;
            T[i]=update(T[i-1], 1, d, x);
        }
        while(m--)
        {
            int l, r, k;
            scanf("%d%d%d", &l, &r, &k);
            int x=query(T[l-1], T[r], 1, d, k);
            printf("%d\n", Hash[x]);
        }
    }
}

poj2104
由於q較小且時間較多,數列分塊能過的題

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;

ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,blo;
int v[500005],bl[500005],atag[500005],tp[100005];
vector<int>ve[505];
//void reset(int x)
//{
//    ve[x].clear();
//    for(int i=(x-1)*blo+1;i<=min(x*blo,n);i++)
//        ve[x].push_back(v[i]);
//    sort(ve[x].begin(),ve[x].end());
//}
void add(int a,int b,int c)
{
    for(int i=a;i<=min(bl[a]*blo,b);i++)
        v[i]+=c;
  //  reset(bl[a]);
    if(bl[a]!=bl[b])
    {
        for(int i=(bl[b]-1)*blo+1;i<=b;i++)
            v[i]+=c;
   //     reset(bl[b]);
    }
    for(int i=bl[a]+1;i<=bl[b]-1;i++)
        atag[i]+=c;
}
int query(int a,int b,int c)
{
    int ans=0;
    for(int i=a;i<=min(bl[a]*blo,b);i++)
        if(v[i]+atag[bl[a]]<c)ans++;
    if(bl[a]!=bl[b])
        for(int i=(bl[b]-1)*blo+1;i<=b;i++)
            if(v[i]+atag[bl[b]]<c)ans++;
  //  cout<<"ans: "<<ans<<endl;
    for(int i=bl[a]+1;i<=bl[b]-1;i++)
    {
        int x=c-atag[i];
        ans+=lower_bound(ve[i].begin(),ve[i].end(),x)-ve[i].begin();
    }
    return ans;
}

int main()
{

    int f,a,b,c,k,q;
    int t;
//    while(t--)
    {
        for(int i=0;i<105;i++)ve[i].clear();
        n=read();
        q=read();
        blo=1000;//這裏注意block的設置,如果設爲sqrt(n)會超時
        mem(atag,0);
        for(int i=1; i<=n; i++)
        {
            v[i]=read();
            tp[i]=v[i];
            bl[i]=(i-1)/blo+1;
        }
        for(int i=1; i<=n; i++)
        {
            ve[bl[i]].push_back(v[i]);
        }
        for(int i=1; i<=bl[n]; i++)
        {
            sort(ve[i].begin(),ve[i].end());
        }
        sort(tp+1,tp+n+1);
        for(int i=1; i<=q; i++)
        {

            a=read();
            b=read();
            k=read();
            int l=1,r=n;
            while(l<=r)
            {
                int m=(l+r)/2;
                if(query(a,b,tp[m])<=(k-1))
                    l=m+1;
                else
                    r=m-1;
            }
            printf("%d\n",tp[r]);
        }
    }
    return 0;
}
/*
6778
5 3
3 1 2 4 5
*/

主席樹同樣能過

#include<cstdio>
#include<algorithm>
#define lson l,m
#define rson m+1,r
using namespace std;

const int maxn=100005;

struct Node{
    int l,r,sum;
}p[maxn<<5];//畢竟有100000顆線段樹。

int T[maxn],a[maxn],Hash[maxn],cnt=0;

int build(int l,int r)
{
    int rt=(++cnt);
    if(l==r)
    {
        return p[rt].sum=0;
    }
    int m=(l+r)>>1;
    p[rt].l=build(lson);//注意這裏的左右子樹不在通過計算得到
    p[rt].r=build(rson);//因爲多棵線段樹的左右節點摻雜,不存在原來線段樹的計算規律。
    return rt;
}
int update(int pre,int l,int r,int x)
{
    int rt=(++cnt);//rt爲新加的一條樹鏈的節點
    p[rt].sum=p[pre].sum+1;
    p[rt].l=p[pre].l;
    p[rt].r=p[pre].r;
    if(l==r)return rt;
    int m=(l+r)>>1;
    if(x<=m)p[rt].l=update(p[pre].l,lson,x);
    else p[rt].r=update(p[pre].r,rson,x);
    return rt;
}
int query(int u,int v,int l,int r,int k)
{
    if(l==r)
    {
        return l;
    }
    int m=(l+r)>>1;
    int num=p[p[v].l].sum-p[p[u].l].sum;
    if(num>=k)return query(p[u].l,p[v].l,lson,k);
    else return query(p[u].r,p[v].r,rson,k-num);
}
int main()
{
    int t;
 //   scanf("%d",&t);
//    while(t--)
    {
        cnt=0;
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            Hash[i]=a[i];
        }
        sort(Hash+1,Hash+1+n);
        int d=unique(Hash+1,Hash+n+1)-Hash-1;
        T[0]=build(1,d);
        for(int i=1;i<=n;i++)
        {
            int x=lower_bound(Hash+1,Hash+d+1,a[i])-Hash;
            T[i]=update(T[i-1],1,d,x);
        }
        while(m--)
        {
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            int x=query(T[l-1],T[r],1,d,k);
            printf("%d\n",Hash[x]);
        }
    }
    return 0;
}

神奇的莫隊+樹狀數組(同樣是分塊,莫隊的時間複雜度很客觀,棒)
貼一個博客->

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
// head
const int N = 1e5+5;
const int M = 5e3+5;
const int B = 1000;

struct BIT {
#define T int
    T tree[N] ;
    inline int lowbit(int x) {
        return x&(-x);
    }
    void add(int x, T add, int n) {
        for (int i = x; i <= n; i += lowbit(i)) {
            tree[i] += add;
        }
    }
    T sum(int x) {
        T ans = 0;
        for (int i = x; i > 0; i -= lowbit(i)) {
            ans += tree[i];
        }
        return ans;
    }
    T query(int k, int n) {
        int l = 1, r = n, ans = n;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (sum(mid) >= k) {
                ans = mid;
                r = mid-1;
            } else {
                l = mid+1;
            }
        }
        return ans;
    }
    void clear(int n) {
        for (int i = 1; i <= n; i++) {
            tree[i] = 0;
        }
    }
#undef T
};

BIT bt;

struct Query {
    int l, r, k, id;
};

bool cmp(const Query &a, const Query &b) {
    int apos = a.l / B, bpos = b.l / B;
    return apos == bpos ? a.r < b.r : apos < bpos;
}

Query query[M];
int a[N];
int dis[N];
int res[M];

void add(int x, int n) {
    bt.add(x, 1, n);
}
void rem(int x, int n) {
    bt.add(x, -1, n);
}
int main() {
    int n, m;
    while (scanf("%d%d", &n, &m) == 2) {
        for (int i = 1; i <= n; i++) {
            scanf("%d", a+i);
            dis[i-1] = a[i];
        }
        sort(dis, dis + n);
        int tot = unique(dis, dis + n) - dis;
        for (int i = 1; i <= n; i++) {
            a[i] = lower_bound(dis, dis + tot, a[i]) - dis + 1;
        }

        for (int i = 0; i < m; i++) {
            scanf("%d%d%d", &query[i].l, &query[i].r, &query[i].k);
            query[i].id = i;
        }
        sort(query, query + m, cmp);

        int l = 1, r = 0;
        for (int i = 0; i < m; i++) {
            while (r < query[i].r) add(a[++r], tot);
            while (l > query[i].l) add(a[--l], tot);
            while (r > query[i].r) rem(a[r--], tot);
            while (l < query[i].l) rem(a[l++], tot);
            res[query[i].id] = bt.query(query[i].k, tot);
        }

        for (int i = 0; i < m; i++) {
            printf("%d\n", dis[res[i]-1]);
        }
        bt.clear(tot);
    }
    return 0;
}
發佈了45 篇原創文章 · 獲贊 27 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章