codeforces 295E Yaroslav and Points (离线操作+离散化+区间合并)

参考链接:http://blog.csdn.net/dyx404514/article/details/8817717

写的很详细,这里就不再赘述,附上我的代码。

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#define lson rt<<1,L,mid
#define rson rt<<1|1,mid+1,R
/*
AC
http://blog.csdn.net/dyx404514/article/details/8817717
*/
using namespace std;
const int maxn=100005;
int n,m;
int nn;  //最后离散后的点的个数
long long val[maxn*2];  //存储所有数据
long long hashval[maxn*2];  //存储离散后的数据
long long a[maxn],aa[maxn]; //存储初始序列
int pos[maxn];  //存储初始序列在hashval中的位置
int cnt=-1;  //用于离散时,统计总共有多少个数
int idx=1;   //用于建树时,获取初始的n个坐标值在hashval中位置的索引
struct Node{
    int num;  //该区间有多少个点。
    long long sum;    //该区间点的横坐标之和。
    long long ans;    //该区间每一对点的距离之和。
}tree[maxn<<3];

struct Query{
    int t,p,d;
    long long l,r;
}q[maxn];

/*
注意:这里二分查找时,用mark标记是查找>=m的数的位置,还是查找<=m的数的位置。
当更新的时候,mark=2即可。
当查询时,查找l的时候,由于l可能不存在,所以我们查找的时候需要查找>=l的最近的数的位置,此时mark=1;
          查找r的时候,由于r可能不存在,所以我们查找的时候需要查找<=r的最近的数的位置,此时mark=2
*/
int binarySearch(long long m,int mark,int length){
    int l=0,r=length+1,mid;
    while(r-l>1){
        mid=(l+r)>>1;
        if(hashval[mid]<=m)
            l=mid;
        else
            r=mid;
    }
    if(hashval[l]==m)
        return l;
    if(mark==1)
        return l+1;
    else
        return l;
}

void pushUp(Node &rt,Node &ls,Node &rs){
    rt.num=ls.num+rs.num;
    rt.sum=ls.sum+rs.sum;
    rt.ans=ls.num*rs.sum-rs.num*ls.sum+ls.ans+rs.ans;  //公式的话,很容易就能推出,这里就不详细说了
}
void build(int rt,int L,int R){
    if(L==R){
        tree[rt].num=tree[rt].sum=tree[rt].ans=0;
        if(idx<=n && L==pos[idx]){
            tree[rt].num=1;
            tree[rt].sum=aa[idx];
            tree[rt].ans=0;
            idx++;
        }
        return;
    }
    int mid=(L+R)>>1;
    build(lson);
    build(rson);
    pushUp(tree[rt],tree[rt<<1],tree[rt<<1|1]);
}
/*
op=1即是加入一个数
op=0即使去除一个数
*/
void update(int rt,int L,int R,int x,int op,int val){
    if(L==R){
        if(op==1){
            tree[rt].num=1;
            tree[rt].sum=val;
            tree[rt].ans=0;
        }
        else{
            tree[rt].num=tree[rt].sum=tree[rt].ans=0;
        }
        return;
    }
    int mid=(L+R)>>1;
    if(x<=mid)
        update(lson,x,op,val);
    else
        update(rson,x,op,val);
    pushUp(tree[rt],tree[rt<<1],tree[rt<<1|1]);
}
Node query(int rt,int L,int R,int l,int r){
    if(l<=L&&R<=r){
        return tree[rt];
    }
    Node tmp,a,b;
    int mid=(L+R)>>1;
    if(r<=mid)
        tmp=query(lson,l,r);
    else if(l>mid)
        tmp=query(rson,l,r);
    else{
        a=query(lson,l,mid);
        b=query(rson,mid+1,r);
        pushUp(tmp,a,b);
    }
    return tmp;
}
int main()
{
    int v,t,p,d;
    int x,y;
    long long l,r;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&v);
        a[i]=v;
        aa[i]=v;
        val[++cnt]=v;
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d",&t);
        if(t==1){
            scanf("%d%d",&p,&d);
            q[i].t=t;
            q[i].p=p;
            q[i].d=d;
            aa[p]+=d; //是累加的
            val[++cnt]=aa[p];
        }
        else{
            scanf("%I64d%I64d",&l,&r);
            q[i].t=t;
            q[i].l=l;  //也可以将查询的l和r加入到离散的数据中去,这样二分查找的时候就不用考虑l和r不存在的问题,
            q[i].r=r;  //查找时,当hashval[mid]==m时返回mid就行,当然这样数组相对就要开大了。
        }
    }
    sort(val,val+cnt+1);
//for(int i=0;i<=cnt;i++)
//   printf("%I64d  ",val[i]);
//printf("\n");

    nn=0;
    hashval[++nn]=val[0];
    for(int i=1;i<=cnt;i++){
        if(val[i]!=val[i-1]){
            hashval[++nn]=val[i];
        }
    }
//for(int i=1;i<=nn;i++)
//    printf("%I64d  ",hashval[i]);
//printf("\n");

    for(int i=1;i<=n;i++)
        aa[i]=a[i];
    sort(aa+1,aa+n+1);

//这里pos数组存储的是初始序列在离散后的数组hashval中的位置,用于建树的初始化
//也可以不采用该方法,在建树时都设为0,然后在对初始序列一个个update即可
    for(int i=1;i<=n;i++){
        pos[i]=binarySearch(aa[i],2,nn);
    }

    build(1,1,nn);
    for(int i=1;i<=m;i++){
        if(q[i].t==1){
            x=binarySearch(a[q[i].p],2,nn);
            update(1,1,nn,x,0,1);
            a[q[i].p]+=q[i].d;
            x=binarySearch(a[q[i].p],2,nn);
            update(1,1,nn,x,1,a[q[i].p]);
        }
        else{
            x=binarySearch(q[i].l,1,nn);
            y=binarySearch(q[i].r,2,nn);
//printf("%I64d %I64d  %d %d\n",q[i].l,q[i].r,x,y);
            if(x>nn||y<1||x>y)
                printf("0\n");  //可能会遇到l>r的情况,参见代码后面的例子
            else
                printf("%I64d\n",query(1,1,nn,x,y).ans);
        }
    }
    return 0;
}

/*
4
20 30 10 -20
5           x  y
2 -25 -20   2  2
1 2 -40
2 21 25     6  5 (这里l>r,一开始忽略了这种情况,导致运行到第二个程序的时候,查询一直往下,无法停止,导致MLE)
1 4 -10
2 -35 -30   1  1

附:叶子节点对应的数据:
-30 -20 -10 10 20 30
*/

 

posted @ 2013-11-15 20:20  辰曦~文若  阅读(322)  评论(0编辑  收藏  举报