hdu 4638 Group (莫队算法 || 离线线段树)

来源:互联网 发布:linux批量管理工具 编辑:程序博客网 时间:2024/06/05 05:48

题目大意:

n个人的编号是从1 - n  ,现在他们无序的站成一排。

第 id 号人和 id-1  id +1 号人是朋友,

朋友之间可以组成group。

一个group的值等于他们人数的平方。

然后有m次询问,问给出的l r 之间能构成group值的和的最大值的group数。


思路分析 (莫队算法):

首先,我们面临着假设你知道这个区间有多少个group 你能知道得到最大值的时候group是怎么分配的么。

令 x = a + b

x^2 = (a+b)^2 = a^2 + 2ab + b^2

可以得到如果得到了group 那么就不要分裂,因为group在一起的才能组成最大值。


那么现在解决询问的问题。

我们用分块莫队算法直接跑。

用ex 记录哪个id的人存在了。

加入的时候通过判断左右两人是否存在。

然后仔细推一下就知道加入与删除的关系了。


(离线线段树)

我们假设所有新加入到树中的数就是孤立的。然后我们再去判断他左边右边是否在树中,如果在树中那么就取消他们所在区间的标记。

借着

5 1

2 1 4 3 5

1 5

更好理解这份代码。



#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#define maxn 100005using namespace std;int bel[maxn];int block;inline void scanf_(int &num){    char in;    bool neg=false;    while(((in=getchar()) > '9' || in<'0') && in!='-') ;    if(in=='-'){        neg=true;        while((in=getchar()) >'9' || in<'0');    }    num=in-'0';    while(in=getchar(),in>='0'&&in<='9')        num*=10,num+=in-'0';    if(neg)        num=0-num;}inline void printf_(int num){    bool flag=false;    if(num<0){        putchar('-');        num=-num;    }    int ans[10],top=0;    while(num!=0){        ans[top++]=num%10;        num/=10;    }    if(top==0)        putchar('0');    for(int i=top-1;i>=0;i--){        char ch=ans[i]+'0';        putchar(ch);    }}struct node{    int st,ed,ans,id;    bool operator < (const node &cmp)const    {        return bel[st]<bel[cmp.st] || (bel[st]==bel[cmp.st] && ed<cmp.ed);    }}Q[maxn];bool cmp_id(node a,node b){    return a.id<b.id;}int a[maxn];int ex[maxn];void modify(int num,int &tans,int add){    if(add==1)    {        if(ex[num-1] && ex[num+1])tans--;        else if(!ex[num-1] && !ex[num+1])tans++;    }    else    {        if(ex[num-1] && ex[num+1])tans++;        else if(!ex[num-1] && !ex[num+1])tans--;    }    ex[num]+=add;}int main(){    int T;    scanf_(T);    while(T--)    {        memset(ex,0,sizeof ex);                int n,m;        scanf_(n),scanf_(m);        block=(int)sqrt(1.0*n);        for(int i=1;i<=n;i++)        {            scanf_(a[i]);            bel[i]=(i-1)/block+1;        }        for(int i=1;i<=m;i++)        {            scanf_(Q[i].st);            scanf_(Q[i].ed);            Q[i].id=i;        }        sort(Q+1,Q+1+m);        int tans=0;        for(int l=1,r=0,i=1;i<=m;i++)        {            if(r<Q[i].ed)            {                for(r=r+1;r<=Q[i].ed;r++)                    modify(a[r],tans,1);                r--;            }            if(r>Q[i].ed)            {                for(;r>Q[i].ed;r--)                    modify(a[r],tans,-1);            }            if(l<Q[i].st)            {                for(;l<Q[i].st;l++)                    modify(a[l],tans,-1);            }            if(l>Q[i].st)            {                for(l=l-1;l>=Q[i].st;l--)                    modify(a[l],tans,1);                l++;            }            Q[i].ans=tans;        }        sort(Q+1,Q+1+m,cmp_id);        for(int i=1;i<=m;i++)        {            printf_(Q[i].ans);            puts("");        }    }    return 0;}

离线线段树。

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define lson num<<1,s,mid#define rson num<<1|1,mid+1,e#define mid ((s+e)>>1)#define maxn 100005using namespace std;int cnt[maxn<<2];void update(int num,int s,int e,int pos,int val){    if(s==e){        cnt[num]+=val;        return;    }    if(pos<=mid)update(lson,pos,val);    else update(rson,pos,val);    cnt[num]=cnt[num<<1]+cnt[num<<1|1];}int query(int num,int s,int e,int l,int r){    if(l<=s && r>=e)return cnt[num];    if(r<=mid)return query(lson,l,r);    else if(l>mid)return query(rson,l,r);    else return query(lson,l,mid)+query(rson,mid+1,r);}struct node{    int st,ed,id,ans;    bool operator < (const node &cmp)const    {        return ed<cmp.ed;    }}Q[maxn];bool cmp_id(node a,node b){    return a.id<b.id;}int pos[maxn];int a[maxn];int main(){    int T;    scanf("%d",&T);    while(T--)    {        int n,m;        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            pos[a[i]]=i;        }        for(int i=1;i<=m;i++)        {            scanf("%d%d",&Q[i].st,&Q[i].ed);            Q[i].id=i;        }        sort(Q+1,Q+1+m);        int index=1;        memset(cnt,0,sizeof cnt);        for(int i=1;i<=n;i++)        {            update(1,1,n,pos[a[i]],1);            if(pos[a[i]+1]<=i && a[i]<n)update(1,1,n,pos[a[i]+1],-1);            if(pos[a[i]-1]<=i && a[i]>1)update(1,1,n,pos[a[i]-1],-1);            while(index<=m && Q[index].ed==i)            {                Q[index].ans=query(1,1,n,Q[index].st,Q[index].ed);                index++;            }        }        sort(Q+1,Q+1+m,cmp_id);        for(int i=1;i<=m;i++)            printf("%d\n",Q[i].ans);    }    return 0;}



1 0