莫队算法 HDU4638

区间问题
暴力解法+离线处理

题目传送门:小Z的袜子

#include 
#include
#include
#include
#include 
using namespace std;
#define maxn 50010
typedef long long ll;
int n,m;
int a[maxn]={0};
int num[maxn];
int unit;
struct  Node{
    int l,r;
    int id;
    friend bool operator <(Node a,Node b){
        if(a.l /unit==b.l/unit)return a.relse return a.l/unitstruct anode{
    ll ans1;
    ll ans2;
    ll gcd(ll a,ll b){
        ll r;
        while(b){
            r=a%b;
            a=b;
            b=r;
        }
        return a;
    }
    void reduce(){
        ll r=gcd(ans2, ans1);
        ans1/=r;ans2/=r;
    }
}ans[maxn];

void work(){
    ll temp=0;
    memset(num, 0, sizeof(num));
    int L=1;
    int R=0;
    for(int i=0;iint r=node[i].r;
        int l=node[i].l;
        int id=node[i].id;
        while(Rwhile(R>r){
            temp-=(ll)num[a[R]]*num[a[R]];
            num[a[R]]--;
            temp+=(ll)num[a[R]]*num[a[R]];
            R--;
        }
        while(Llong long)num[a[L]]*num[a[L]];
            num[a[L]]--;
            temp += (long long)num[a[L]]*num[a[L]];
            L++;
        }
        while(L>l){
            L--;
            temp -= (long long)num[a[L]]*num[a[L]];
            num[a[L]]++;
            temp += (long long)num[a[L]]*num[a[L]];
        }
        ans[id].ans1=temp-(r-l+1);
        ans[id].ans2=(ll)(r-l+1)*(r-l);
        ans[id].reduce();
    }
}
int main(){
    while(cin>>n>>m){
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        for(int i=0;iscanf("%d%d",&node[i].l,&node[i].r);

        }
         unit=sqrt(n);
        sort(node,node+m);
        work();
        for(int i=0;iprintf("%lld/%lld\n",ans[i].ans1,ans[i].ans2);
        }
    }
    return 0;
}
#include 
#include
#include
#include
#include 
using namespace std;
#define maxn 50010
typedef long long ll;
int n,m;
int a[maxn]={0};
int num[maxn];
int unit;
struct  Node{
    int l,r;
    int id;
    friend bool operator <(Node a,Node b){
        if(a.l /unit==b.l/unit)return a.relse return a.l/unitstruct anode{
    ll ans1;
    ll ans2;
    ll gcd(ll a,ll b){
        ll r;
        while(b){
            r=a%b;
            a=b;
            b=r;
        }
        return a;
    }
    void reduce(){
        ll r=gcd(ans2, ans1);
        ans1/=r;ans2/=r;
    }
}ans[maxn];
//莫队算法
ll temp=0;
void ad(int pos){//需根据暴力思路修改
    temp-=(ll)num[a[pos]]*num[a[pos]];//
    num[a[pos]]++;
    temp+=(ll)num[a[pos]]*num[a[pos]];//

}
void remove(int pos){//
    temp-=(ll)num[a[pos]]*num[a[pos]];
    num[a[pos]]--;
    temp+=(ll)num[a[pos]]*num[a[pos]];
}

void work(){

    memset(num, 0, sizeof(num));
    int L=1;
    int R=0;
    for(int i=0;iint r=node[i].r;
        int l=node[i].l;
        int id=node[i].id;
        while(Rwhile(R>r){
            remove(R);
            R--;
        }
        while(Lwhile(L>l){
            L--;
            ad(L);
        }
        ans[id].ans1=temp-(r-l+1);
        ans[id].ans2=(ll)(r-l+1)*(r-l);
        ans[id].reduce();
    }
}
int main(){
    while(cin>>n>>m){
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        for(int i=0;iscanf("%d%d",&node[i].l,&node[i].r);

        }
         unit=sqrt(n);
        sort(node,node+m);
        work();
        for(int i=0;iprintf("%lld/%lld\n",ans[i].ans1,ans[i].ans2);
        }
    }
    return 0;
}

HDU4638 Group

思路分析
t数组初始化为0,将L-R区间的数ai对应于t[ai]=1;
当其左右都为0时说明是新的一段,temp+1;(连续多个1为一个段)
当其左右都为1时说明其连接起来原先的两端,变为了一段,temp-1;
同理,当t[ai]变为0时要考虑这两种变化

#include 
#include
#include
#include
#include 
using namespace std;
#define maxn 100010

int n,m;
int a[maxn];
int t[maxn];
int unit;
struct node{
    int l,r;
    int order;
    friend bool operator <(node a,node b){
        if(a.l/unit==b.l/unit)return a.relse return a.l/unitq[maxn];
int ans[maxn];

int temp=0;
void ad(int pos){
    int i=a[pos];
    t[i]=1;
    if(t[i-1]&&t[i+1])temp--;
    if(!t[i-1]&&!t[i+1])temp++;
}
void remove(int pos){
    int i=a[pos];
    t[i]=0;
    if(t[i-1]&&t[i+1])temp++;
    if(!t[i-1]&&!t[i+1])temp--;
}

void work(){
    int L=1;
    int R=0;
    temp=0;
    memset(t,0,sizeof(t));
    for(int i=0;i<m;i++){
        int l=q[i].l;
        int r=q[i].r;
        int order=q[i].order;
        while(Rwhile(R>r){
            remove(R);
            R--;
        }
        while(Lwhile(L>l){
            L--;
            ad(L);
        }
        ans[order]=temp;
    }
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n>>m;
        unit=sqrt(n);
        for(int i=1;i<=n;i++)scanf("%d",a+i);
        for(int i=0;i<m;i++){
            q[i].order=i;
            scanf("%d%d",&q[i].l,&q[i].r);
        }
        sort(q,q+m);
        work();
        for(int i=0;i<m;i++)cout<return 0;
}

你可能感兴趣的:(莫队算法,ACM)