炸弹

来源:互联网 发布:一组数据如何找规律 编辑:程序博客网 时间:2024/04/28 04:29

题意:在一些坐标上有一些炸弹。。有两个操作

          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 100010int 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&lt;=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