码迷,mamicode.com
首页 > 编程语言 > 详细

hdu5212 Code 莫队算法

时间:2015-05-01 13:26:57      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:

这道题需要一些莫队算法的知识
定义记号f(A,B)表示询问区间A,B时的答案
用记号+表示集合的并
利用莫队算法我们可以计算出任意f(A,A)的值
不妨假设A=[l1,r1],B=[l2,r2],C=[r1+1,l2?1]
容易知道f(A,B)=f(A+B+C,A+B+C)+f(C,C)?f(A+C,A+C)?f(C+B,C+B)
因此一个询问被拆成四个可以用莫队算法做的询问
总的时间复杂度为O(msqrt(n))
(以上是官方题解)
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
const int N = 30000*4 + 10;


int pos[N];
struct pp{
    int l,r,id;
    int ans;
}p[N];
int cmp(pp a,pp b){
    if(pos[a.l]==pos[b.l]) return a.r < b.r;
    return a.l < b.l;
}
int cmp2(pp a,pp b){
    return a.id < b.id;
}


struct que{
    int l1,l2,r1,r2;
}q[N];
int block,n,k,m,num;
int a[N],cnt[N],answer;
LL x;


map<LL,int> mm;


void update(int x,int v){
    int val = k - a[x];
    if(val <= 0) return ;
    answer += cnt[val]*v;
    cnt[a[x]] += v;
}


void solve(){
    int l,r;
    answer = 0;
    for(int i=1,l=1,r=0;i<=num;i++){//按块进行更新
        for(;r<p[i].r;r++)
            update(r+1,1);
        for(;r>p[i].r;r--)
            update(r,-1);
        for(;l<p[i].l;l++)
            update(l,-1);
        for(;l>p[i].l;l--)
            update(l-1,1);
        p[i].ans = answer;
    }
}


int main(){
    while(scanf("%d",&n)!=EOF){
        mm.clear();
        num = 0;
        block = (int)sqrt(n)+1;
        for(int i=1;i<=n;i++) pos[i] = i/block + 1;
        scanf("%d",&k);
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            int l1,l2,r1,r2;
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            q[i].l1 = l1 , q[i].r1 = r1 , q[i].l2 = l2 , q[i].r2 = r2;
            p[++num].l = l1 , p[num].r = l2-1 ;
            x = l1*40000+(l2-1);
            mm[x] = num;
            p[num].id = num;


            p[++num].l = r1+1 , p[num].r = r2 ;
            x = (r1+1)*40000+r2;
            mm[x] = num;
            p[num].id = num;


            if(l2-1 >= r1+1){
                p[++num].l = r1+1 , p[num].r = l2-1 ;
                x = (r1+1)*40000+(l2-1);
                mm[x] = num;
                p[num].id = num;
            }


            p[++num].l = l1 , p[num].r = r2 ;
            x = l1*40000+r2;
            mm[x] = num;
            p[num].id = num;
        }
        sort(p+1,p+1+num,cmp);
        solve();
        sort(p+1,p+1+num,cmp2);
        for(int i=1;i<=m;i++){
            int l1,l2,r1,r2;
            l1 = q[i].l1 , l2 = q[i].l2 , r1 = q[i].r1 , r2 = q[i].r2 ;
            LL ans = 0;


            x = l1*40000+r2;
            ans += p[mm[x]].ans;


            if(l2-1>=r1+1){
                x = (r1+1)*40000+(l2-1);
                ans += p[mm[x]].ans;
            }




            x = (r1+1)*40000+r2;
            ans -= p[mm[x]].ans;


            x = l1*40000+(l2-1);
            ans -= p[mm[x]].ans;


            printf("%lld\n",ans);
        }
    }
    return 0;
}

hdu5212 Code 莫队算法

标签:

原文地址:http://blog.csdn.net/alpc_wt/article/details/45418757

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!