Ahoi2013 作业

3236: [Ahoi2013]作业

Time Limit: 100 Sec  Memory Limit: 512 MB

Description

Input

Output

Sample Input

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

Sample Output

2 2
1 1
3 2
2 1

HINT

N=100000,M=1000000

Source

By wangyisong1996加强数据

莫队+树状数组

用莫队解决[l,r]的问题

两个树状数组,以权值为下标,一个记录权值为i的是否出现,一个记录权值为i的出现了几次

蒟蒻初学,常数巨大。。。

向各位大佬请教如何优化

#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 100001
using namespace std;
int n,m,size,l=1,r,tmp;
int key[N],sum[N],c[2][N];
int ans[N*10][2];
struct node
{
    int l,r,a,b;
    int bl,id;
    int ans1,ans2;
}e[N*10];
bool cmp(node p,node q)
{
    if(p.bl!=q.bl) return p.bl<q.bl;
    return p.r<q.r;
}
int lowbit(int x)
{
    return x&(-x);
}
void change(int k,int w,int h)
{
    while(k<=n) { c[h][k]+=w; k+=lowbit(k);}
}
int query(int k,int h)
{
    int tot=0;
    while(k) { tot+=c[h][k]; k-=lowbit(k);}
    return tot;
}
void update(int k,int w)
{
    sum[key[k]]+=w; 
    change(key[k],w,1);
    if(w==1&&sum[key[k]]==1) change(key[k],1,0);
    else if(w==-1&&!sum[key[k]]) change(key[k],-1,0);
}
int main()
{
    scanf("%d%d",&n,&m);
    size=sqrt(n);
    for(int i=1;i<=n;i++) scanf("%d",&key[i]);
    for(int i=1;i<=m;i++) 
    {
        scanf("%d%d%d%d",&e[i].l,&e[i].r,&e[i].a,&e[i].b);
        e[i].bl=(e[i].l-1)/size+1;
        e[i].id=i;
    }
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        while(e[i].l<l) update(--l,1);
        while(e[i].l>l) update(l++,-1);
        while(e[i].r<r) update(r--,-1);
        while(e[i].r>r) update(++r,1);
        e[i].ans1=query(e[i].b,0)-query(e[i].a-1,0);
        e[i].ans2=query(e[i].b,1)-query(e[i].a-1,1);
    }
    for(int i=1;i<=m;i++) ans[e[i].id][0]=e[i].ans2 , ans[e[i].id][1]=e[i].ans1;
    for(int i=1;i<=m;i++) printf("%d %d
",ans[i][0],ans[i][1]);
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6773084.html