您的位置:首页 > 理论基础 > 数据结构算法

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

2017-09-28 17:55 375 查看
法一:

线段树——

用一棵线段树+主席树

线段树就是拿来统计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<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
const int N=1e5+5;
int exi
;
int n,m,aa
,pos
,block;
ll ans
;
struct data{
int l,r,id;
}a
;
int cmp(data a,data b)
{
if(pos[a.l]==pos[b.l]) return a.r<b.r;
return 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<a[i].l;pl++){
exi[aa[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(;pr<a[i].r;pr++){
exi[aa[pr+1]]++;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: