2019南京網絡賽-A-The beautiful values of the palace(樹狀數組 二維偏序)

題目鏈接

題意

一個螺旋的矩陣,大小爲n*n,n一定爲奇數。有m個位置有值,值就是螺旋矩陣上的值,其他沒有列舉的位置都爲0. 給了x1,y1,x2,y2,求矩形區域(x1,y1)(x2,y2)內所有數的綜合。

思路

求矩形區域,可以轉化爲求四個前綴和。但是1e6限制了不能用二維樹狀數組,所以求前綴和的時候按照Y從小到大的順序,將二維轉化爲一維。

會爆int,用ll存

參考


#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

ll getNum(ll x,ll y,ll n) //得到螺旋矩陣的數
{
    x = x-n/2-1;
    y = y-n/2-1;
    ll t = max(abs(x),abs(y));//第幾個螺旋
    ll ans;
    if(x>=y) ans = n*n-4*t*t-2*t-x-y;
    else ans = n*n-4*t*t+2*t+x+y;
    return ans;
}

ll getDigit(ll x) //求數的各位數字和
{
    ll ans = 0;
    while(x){
        ans += x%10;
        x /=10;
    }
    return ans;
}
const int N = 1e6+10;
ll c[N];ll ans[N]; //c是樹狀數組,ans是第i次訪問的答案
ll n,m,p,tot;

ll lowbit(ll i){ return i & -i; }
void update(ll i,ll v)
{
    while(i<=n){
        c[i] += v;
        i += lowbit(i);
    }
}
ll sum(ll i)
{
    ll ret = 0;
    while(i>0){
        ret += c[i];
        i -= lowbit(i);
    }
    return ret;
}

struct node1 // 存有值的點
{
    ll x,y,w;
}point[N];
bool cmp1(node1 a,node1 b){return a.y<b.y;}


struct node2 //存訪問的前綴和
{
    ll x,y,id,flag;
    node2(){}
    node2(ll _x,ll _y,ll _id,ll _flag):
        x(_x),y(_y),id(_id),flag(_flag){}
}q[N*4];
bool cmp2(node2 a,node2 b){return a.y<b.y;}


void solve()
{
    memset(c,0,sizeof(c));
    memset(ans,0,sizeof(ans));
    sort(point+1,point+1+m,cmp1);
    sort(q+1,q+1+tot,cmp2);
    
    int k = 1;
    for(int i=1;i<=tot;i++){
        while(k<=m && q[i].y>=point[k].y){//有值的點沒有添加完 && 訪問前綴和的y值大於等於添加點的y值
            if(point[k].x!=0) update(point[k].x,point[k].w);//添加點,一直到樹狀數組c存的是小於等於y的前綴和
            k++;
        }
        if(q[i].x!=0) {
            ans[q[i].id] += sum(q[i].x)*q[i].flag;
        }
    }
}

int main()
{
    int T; scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&p);
        for(int i=1;i<=m;i++){
            int x,y;scanf("%d%d",&x,&y);
            point[i].x = x; point[i].y = y; point[i].w = getDigit(getNum(x,y,n));
        }

        tot = 0;
        for(int i=1;i<=p;i++){
            int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            q[++tot] = node2(x2,y2,i,1);
            q[++tot] = node2(x1-1,y1-1,i,1);
            q[++tot] = node2(x1-1,y2,i,-1);
            q[++tot] = node2(x2,y1-1,i,-1);
        }
        solve();
        for(int i=1;i<=p;i++){
            printf("%lld\n",ans[i]);
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章