zoukankan      html  css  js  c++  java
  • 2019南京网路赛 A.The beautiful values of the palace (主席树)

    传送门

    题意

    给一个 (n imes n) 的矩阵,以螺旋线的形式给每个位置的预设值,有 (m) 个位置的值为本身的预设值,其余位置为 (0),然后 (p) 组询问,每组询问回答子矩阵中的总值为多少。

    题解

    有不少题解都是用离线树状数组的方法解决的,但是如果学习了主席树过后,可以发现主席树是解决这种二维偏序问题的利器。
    首先对于 (m) 个有值得点,(O(1)) 地求出它得价值,不会得可以去学习一下螺旋矩阵
    因为坐标在 (2cdot 10^6) 范围里,对于主席树来说有点大了,所以把 (y) 坐标离散化,这样主席树开 (mlog_2m) 个点就好。
    然后把每个点以 (x) 坐标从小到大排序之后依次更改主席树,这颗主席树相当于维护了 (m) 个线段树,每个线段树统计已加入的点 (y) 坐标在区间 ([l,r]) 中的所有点的总价值是多少。
    对于每个询问,看 ([x1,x2]) 这个区间里的信息是由哪两颗线段树的差值形成的,然后查询这两颗线段树在区间 ([y1,y2]) 中的差值总和,就是答案了,当然由于离散化,所以 (y1,y2) 一定要以离散化后的区间为准。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int MAXN=1e5+10;
    int n,m,p,root[MAXN];
    int b[MAXN],cnt;
    struct Point{
        int x,y;
        LL v;
        void getv(){
            int mid=(n+1)>>1;
            int tx=x-mid,ty=y-mid;
            LL c=max(abs(tx),abs(ty));
            LL id=c*(c-1)*8/2;
            if(ty==c&&-c<=tx&&tx<c) id+=c-tx;
            else if(tx==-c&&-c<=ty&&ty<c) id+=c*2+c-ty;
            else if(ty==-c&&-c<tx&&tx<=c) id+=2*c*2+c+tx;
            else id+=3*c*2+c+ty;
            LL temp=1ll*n*n-id;
            v=0;
            while(temp) v+=temp%10,temp/=10;
        }
        friend bool operator < (const Point& a,const Point& b){
            return a.x<b.x;
        }
    }pt[MAXN];
    
    struct HjtTree{
        #define mid ((l+r)>>1)
        LL sum[MAXN*40];
        int ls[MAXN*40],rs[MAXN*40],tot;
        void build(int& id,int l,int r){
            id=++tot;sum[id]=0;
            if(l==r) return;
            build(ls[id],l,mid);
            build(rs[id],mid+1,r);
        }
        void update(int pre,int& id,int l,int r,int pos,LL x){
            id=++tot;sum[id]=sum[pre]+x;ls[id]=ls[pre];rs[id]=rs[pre];
            if(l==r) return;
            if(pos<=mid) update(ls[pre],ls[id],l,mid,pos,x);
            else update(rs[pre],rs[id],mid+1,r,pos,x);
        }
        LL ask(int u,int v,int l,int r,int L,int R){
            if(L<=l&&r<=R) return sum[v]-sum[u];
            LL res=0;
            if(L<=mid) res+=ask(ls[u],ls[v],l,mid,L,R);
            if(R>mid) res+=ask(rs[u],rs[v],mid+1,r,L,R);
            return res;
        }
        #undef mid
    }tree;
    
    void solve(){
        scanf("%d%d%d",&n,&m,&p);
        cnt=0;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&pt[i].x,&pt[i].y);pt[i].getv();
            b[++cnt]=pt[i].y;
        }
        sort(b+1,b+cnt+1);cnt=unique(b+1,b+cnt+1)-b-1;
        for(int i=1;i<=m;i++) pt[i].y=lower_bound(b+1,b+cnt+1,pt[i].y)-b;
        sort(pt+1,pt+m+1);
        tree.tot=0;
        tree.build(root[0],1,cnt);
        for(int i=1;i<=m;i++) tree.update(root[i-1],root[i],1,cnt,pt[i].y,pt[i].v);
        for(int i=1,x1,y1,x2,y2;i<=p;i++){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            int u=lower_bound(pt+1,pt+m+1,(Point){x1,0,0})-pt-1;
            int v=upper_bound(pt+1,pt+m+1,(Point){x2,0,0})-pt-1;
            int l=lower_bound(b+1,b+cnt+1,y1)-b;
            int r=upper_bound(b+1,b+cnt+1,y2)-b-1;
            if(u>v||l>r) printf("0
    ");
            else printf("%lld
    ",tree.ask(root[u],root[v],1,cnt,l,r));
        }
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("data.in","r",stdin);
        freopen("data.out","w",stdout);
    #endif
        int T;scanf("%d",&T);
        while(T--) solve();
        return 0;
    }
    
  • 相关阅读:
    百度练习题 统计元音字母
    guess number
    LPTHW 结束了
    大坑
    LPTHW 笨办法学python 40章 类
    LPTHW 笨办法学python 37章 python关键字/关键词介绍
    dis进行反编译
    LPTHW 笨办法学python 33章
    eclipse安装详解以及遇到的问题
    安装eclipse错误Could not create the Java virtual machine
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12307078.html
Copyright © 2011-2022 走看看