题意:在一些坐标上有一些炸弹。。有两个操作
1、移动炸弹,,把一个炸弹从一个坐标移到另一个坐标。
2、询问一段坐标中所有炸弹坐标中大坐标减去小坐标。
思路:离散化,把所有可能出现的坐标点找出来排好序后,去重。
把所有坐标都映射到他所对应的在数组的索引号,用map实现。
用res记录段的坐标差和,sum记录所有坐标之和,cnt记录有多少个地雷。
更新res=res1+res2+cnt1*sum2-cnt2*sum1;
sum=sum1+sum2;
cnt=cnt1+cnt2;
查找时的结果res要依靠sum和cnt所以返回类型为tree,并且更新只在返回的结构体中更新。
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
#define N 100010
int n,q;
struct tree
{
int left,right;
int mid;
long long res,sum,cnt;
}t[N*12];
map<long long,int> m;
struct car
{
int flag;
long long from,to;
}ask[N];
long long hi[2*N];
int nhi;
long long go[N];
void build(int cur,int l,int r)
{
t[cur].mid=(l+r)>>1;
t[cur].left=l;
t[cur].right=r;
t[cur].res=t[cur].sum=t[cur].cnt=0;
if (l!=r)
{
build(cur<<1,l,t[cur].mid);
build(cur<<1|1,t[cur].mid+1,r);
}
}
void add(int cur,int l)
{
if (t[cur].left==t[cur].right)
{
t[cur].sum=hi[l];
t[cur].cnt=1;
t[cur].res=0;
return;
}
int L=cur<<1,R=cur<<1|1;
int m=t[cur].mid;
if (l<=m)
add(L,l);
else
add(R,l);
t[cur].sum=t[L].sum+t[R].sum;
t[cur].cnt=t[L].cnt+t[R].cnt;
t[cur].res=t[L].res+t[R].res+t[L].cnt*t[R].sum-t[R].cnt*t[L].sum;
}
void remove(int cur,int l)
{
if (t[cur].left==t[cur].right)
{
t[cur].sum=0;
t[cur].cnt=0;
t[cur].res=0;
return;
}
int L=cur<<1,R=cur<<1|1;
int m=t[cur].mid;
if (l<=m)
remove(L,l);
else
remove(R,l);
t[cur].sum=t[L].sum+t[R].sum;
t[cur].cnt=t[L].cnt+t[R].cnt;
t[cur].res=t[L].res+t[R].res+t[L].cnt*t[R].sum-t[R].cnt*t[L].sum;
}
tree query(int cur,int l,int r)
{
if (l<=t[cur].left && r>=t[cur].right)
{
return t[cur];
}
int m=t[cur].mid;
int L=cur<<1,R=cur<<1|1;
if (r<=m)
return query(L,l,r);
else if (l>m)
return query(R,l,r);
tree LL=query(L,l,r);
tree RR=query(R,l,r);
tree ans;
ans.res=LL.res+RR.res+RR.sum*LL.cnt-LL.sum*RR.cnt;
ans.sum=LL.sum+RR.sum;
ans.cnt=LL.cnt+RR.cnt;
return ans;
}
int main()
{
freopen("in.txt","r",stdin);
int i,j,k;
int nc;
cin>>nc;
while (nc--)
{
scanf("%d",&n);
for (i=0;i<n;i++)
{
scanf("%d",&k);
go[i]=k;
hi[i]=k;
}
nhi=n;
scanf("%d",&q);
for (int ii=0;ii<q;ii++)
{
scanf("%d%d%d",&k,&i,&j);
if (k==1)
{
go[i-1]+=j;
hi[nhi++]=go[i-1];
}
else
{
hi[nhi++]=i;
hi[nhi++]=j;
}
ask[ii].flag=k;
ask[ii].from=i;
ask[ii].to=j;
}
for (i=0;i<n;i++)
go[i]=hi[i];
sort(hi,hi+nhi);
j=1;
for (i=1;i<nhi;i++)
if (hi[i]!=hi[i-1])
hi[j++]=hi[i];
nhi=j;
for (i=0;i<nhi;i++)
m[hi[i]]=i;
build(1,0,nhi-1);
for (i=0;i<n;i++)
add(1,m[go[i]]);
for (i=0;i<q;i++)
{
if (ask[i].flag==1)
{
remove(1,m[go[ask[i].from-1]]);
// cout<<go[ask[i].from]<<' ';
go[ask[i].from-1]+=ask[i].to;
// cout<<go[ask[i].from]<<endl;
add(1,m[go[ask[i].from-1]]);
}
else
{
// cout<<ask[i].from<<' '<<ask[i].to<<' '<<m[ask[i].from]<<' '<<m[ask[i].to]<<endl;
printf("%lld\n",query(1,m[ask[i].from],m[ask[i].to]).res);
}
}
}
return 0;
}
贪玩的xie
Time Limit: 5000 ms Memory Limit: 65535 kB Solved: 25 Tried: 222
Submit
Status
Best Solution
Back
Description
Xie是一个很无聊的人,他最喜欢的事就是随手拿一些可怕的东西来玩。
现在,xie在x轴上放了n个地雷。第一个地雷的坐标是x1,第二个的坐标是x2,..,第n个的坐标是xn。
现在xie有m个关于这些地雷的询问,每个询问分为以下两类:
1.把第pj个地雷从所在的位置xpj移动到xpj+dj。数据保证,每次移动之后,每个地雷的坐标都不同。
2.为了评估地雷爆炸的威力,计算线段[lj,rj]上的每对地雷的距离之和。也就是说,要计算
Input
第一行一个整数T,表示数据组数。
每组数据第一行一个整数n(1<=n<=10^5),地雷的数量。第二行包含n个不同的整数x1,x2,…,xn,表示地雷的坐标。
第三行有一个整数m,代表询问的数量(1<=m<=10^5).接下来m行描述这些询问。第j行的第一个整数tj(1<=tj<=2),表示询问的类型。如果tj=1,那么接下来会有两个整数pj和 dj(1<=pj<=n,|dj|<=1000)。如果tj=2,那么会有两个整数lj,rj(-10^9 < lj <= rj <= 10^9)
保证任意时刻,所有的地雷都在不同的坐标上。
Output
对于每个第2类型的询问,输出一行答案。输出答案请按询问出现的顺序来输出。
Sample Input
1
8
36 50 28 -75 40 -60 -95 -48
20
2 -61 29
1 5 -53
1 1 429
1 5 130
2 -101 -71
2 -69 53
1 1 404
1 5 518
2 -101 53
2 50 872
1 1 -207
2 -99 -40
1 7 -389
1 6 -171
1 2 464
1 7 -707
1 1 -730
1 1 560
2 635 644
1 7 -677
Sample Output
176
20
406
1046
1638
156
0