9.27 数据结构noip模拟——不正常团伙

法一:
线段树——
用一棵线段树+主席树
线段树就是拿来统计sum的 (sigma a)
主席树就是拿来统计个数为2的数的和del
主席树的具体操作:
a[i] i前有一个数=a[i] 则在第i棵树的第i个位置 +a[i]
a[i] i前有两个数=a[i] :
a[i]- 4 4 4
del- -4 +4 0 这样查询前三个时sigmadel=0 查询后两个时sigma=4
再比如
a[i] - 4 4 4 4
del 0 -4 +4 0
当查询[l,r]时 查询第r棵树的l,r区间
(这个做法详见谢大佬博客)

法二:
莫队——
没什么好说的看代码就行
考试时想到了莫队但是很执念的认为莫队就要分块预处理……说到底还是对莫队不熟。
以及最近很喜欢犯一些sb错误?
调了那么久,就是因为
else if(exi[aa[pr]]==1) rt+=aa[pr];
把pr写成了pl ……

#include
#include
#include
#include
using namespace std;
#define ll long long
const int N=1e5+5;
int exi[N];
int n,m,aa[N],pos[N],block;
ll ans[N];
struct data{
    int l,r,id;
}a[N];
int cmp(data a,data b)
{
    if(pos[a.l]==pos[b.l]) return a.rreturn pos[a.l]<pos[b.l];
}
int main()
{
    freopen("abnormal.in","r",stdin);
    freopen("abnormal.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&aa[i]);
    block=sqrt(n);
    for(int i=1;i<=n;i++)
    pos[i]=(i-1)/block+1;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a[i].l,&a[i].r);
        a[i].id=i;
    }
    sort(a+1,a+1+m,cmp);
    int pl=a[1].l,pr=a[1].r;ll rt=0;
    for(int i=a[1].l;i<=a[1].r;i++){
        exi[aa[i]]++;
        if(exi[aa[i]]==2) rt-=aa[i];
        else if(exi[aa[i]]==3) rt+=3*aa[i];
            else rt+=aa[i];
    }
    ans[a[1].id]=rt;
    for(int i=2;i<=m;i++){
        for(;pl//if(exi[aa[pl]]==2) rt-=3*aa[pl];
            if(exi[aa[pl]]==2||!exi[aa[pl]]) rt-=(exi[aa[pl]]+1)*aa[pl];
            else if(exi[aa[pl]]==1) rt+=aa[pl];//2->1
                else rt-=aa[pl];
        }
        for(;pl>a[i].l;pl--){
            exi[aa[pl-1]]++;
            if(exi[aa[pl-1]]==2) rt-=aa[pl-1];
            else if(exi[aa[pl-1]]==3) rt+=3*aa[pl-1];
                else rt+=aa[pl-1];
        }
        for(;pr1]]++;
            if(exi[aa[pr+1]]==2) rt-=aa[pr+1];
            else if(exi[aa[pr+1]]==3) rt+=3*aa[pr+1];
                else rt+=aa[pr+1];
        }
        for(;pr>a[i].r;pr--){
            exi[aa[pr]]--;
            if(exi[aa[pr]]==2) rt-=3*aa[pr];
            else if(exi[aa[pr]]==1) rt+=aa[pr];//2->1!!!
                else rt-=aa[pr];
        }
        ans[a[i].id]=rt;
    }
    for(int i=1;i<=m;i++)
    printf("%I64d\n",ans[i]);
    return 0;
}

你可能感兴趣的:(莫队,------模拟考试-----)