2019ICPC南京网络赛 A.The beautiful values of the palace 离线树状数组或者CDQ分治或者主席树

Here is a square matrix of n * nn∗n, each lattice has its value (nn must be odd), and the center value is n * nn∗n. Its spiral decline along the center of the square matrix (the way of spiral decline is shown in the following figure:)The grid in the lower left corner is (1,1) and the grid in the upper right corner is (n , n)

Now I can choose mm squares to build palaces, The beauty of each palace is equal to the digital sum of the value of the land which it is located. Such as (the land value is 123213123213,the beautiful values of the palace located on it is 1+2+3+2+1+3=121+2+3+2+1+3=12) (666666 -> 1818) (456456 ->1515)

Next, we ask pp times to the sum of the beautiful values of the palace in the matrix where the lower left grid(x_1,y_1x1​,y1​), the upper right square (x_2,y_2x2​,y2​).

Input

The first line has only one number TT .Representing TT-group of test data (T\le 5)(T≤5)

The next line is three number: n \ m \ pn m p

The mm lines follow, each line contains two integers the square of the palace (x, y )(x,y)

The pp lines follow, each line contains four integers : the lower left grid (x_1,y_1)(x1​,y1​) the upper right square (x_2,y_2)(x2​,y2​)

Output

Next, p_1+p_2...+p_Tp1​+p2​...+pT​ lines: Represent the answer in turn(n \le 10^6)(m , p \le 10^5)(n≤106)(m,p≤105)

样例输入复制

1
3 4 4
1 1
2 2
3 3
2 3
1 1 1 1
2 2 3 3
1 1 3 3
1 2 2 3

样例输出复制

5
18
23
17

题意:

给一个n*n的蛇形矩阵,n为奇数。给定m个宫殿,处在每个宫殿位置(x,y)的点有一个beautiful value等于此点蛇形矩阵上数字的各位数和。p个询问, 给出一个矩形左下角的点(x1,y1)和右上角的点(x2,y2),问被矩形覆盖的所有宫殿的value总和是多少。

分析:

离线树状数组

类似于求矩阵的前缀和的思想,对于询问左下角(x1,y1),右上角(x2,y2)

该询问答案为a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1],我们对x坐标建立树状数组,插入y的值,统计x值的贡献即可,看一下代码就明白了。即我们把询问拆成四个前缀和,和m个点一起离线,树状数组更新答案即

CDQ分治

模板题

主席树

待理解

 

树状数组

#include <bits/stdc++.h>
using namespace std;
const int maxm=1e6+100;
typedef long long LL;
const int N=1e6;
struct Node
{
    LL x,y;
    LL id,w,tag;
} q[maxm];
LL sum[maxm],ans[maxm];
LL n,m,Q,cnt,t;
inline int lowbit(int x)
{
    return x&(-x);
}
inline void ins(int x,LL val)
{
    for(int i=x; i<=N; i+=lowbit(i))
        sum[i]+=val;
}
inline int ask(LL x)
{
    LL res=0;
    for(int i=x; i; i-=lowbit(i))
        res+=sum[i];
    return res;
}
inline bool comp(Node p,Node q)
{
    return (p.x<q.x)||((p.x==q.x)&&(p.tag>q.tag));
}
inline LL cal(LL x,LL y)
{
    LL layer=std::min(std::min(x, y),n-std::max(x, y)+1);
    if((layer<<1)>n)
        return n*n;
    LL st=n*n-(n-(layer<<1)+2)*(n-(layer<<1)+2)+1;
    if (x>=y)
        return st+((n-layer)<<1)+2-x-y;
    return st+((n-(layer<<1)+1)<<1)+x+y-(layer<<1);
}
inline LL split(LL x)
{
    LL res=0;
    while(x)
    {
        res+=x%10;
        x/=10;
    }
    return res;
}
inline void work()
{
    scanf("%lld%lld%lld",&n,&m,&Q);
    cnt=0;
    memset(sum,0,sizeof(sum));
    LL x,y;
    for(int i=1; i<=m; i++)
    {
        scanf("%lld%lld",&x,&y);
        q[++cnt]=Node{x,y,0,split(cal(x,y)),2};
    }
    LL x1,y1,x2,y2;
    for(int i=1; i<=Q; i++)
    {
        scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
        ans[i]=0;
        q[++cnt]=Node{x2,y2,i,0,1};
        q[++cnt]=Node{x2,y1-1,i,0,-1};
        q[++cnt]=Node{x1-1,y2,i,0,-1};
        q[++cnt]=Node{x1-1,y1-1,i,0,1};
    }
    sort(q+1,q+cnt+1,comp);
    for(int i=1; i<=cnt; i++)
    {
        if(q[i].tag==2)
            ins(q[i].y,q[i].w);
        else
            ans[q[i].id]+=q[i].tag*ask(q[i].y);
    }
    for(int i=1; i<=Q; i++)
        printf("%lld\n",ans[i]);
}
signed main()
{
    scanf("%lld",&t);
    for(int i=1; i<=t; i++)
        work();
    return 0;
}

CDQ分治

 

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<sstream>
#include<stack>
#include<string>
#include<set>
#include<vector>
using namespace std;
#define PI acos(-1.0)
#define EXP exp(1)
#define pppp cout<<endl;
#define EPS 1e-8
#define LL long long
#define ULL unsigned long long     //1844674407370955161
#define INT_INF 0x3f3f3f3f      //1061109567
#define LL_INF 0x3f3f3f3f3f3f3f3f //4557430888798830399
// ios::sync_with_stdio(false);
// 那么cin, 就不能跟C的 scanf,sscanf, getchar, fgets之类的一起使用了。
const int dr[]= {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[]= {-1, 1, 0, 0, -1, 1, -1, 1};
inline int read()//输入外挂
{
    int ret=0, flag=0;
    char ch;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        ret = ch - '0';
    while((ch=getchar())>='0'&&ch<='9')
        ret=ret*10+(ch-'0');
    return flag ? -ret : ret;
}

const int N=1000050;
int c[N];
int ans[N];
int n,tim;
int lowbit(int x)
{
    return x&(-x);
}
void add(int x,int w)
{
    while(x<=n)
    {
        c[x]+=w;
        x+=lowbit(x);
    }
}
int getsum(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
struct Node
{
    int t;
    int x,y;
    int w,ot,id;
    Node() {}
    Node(int t,int x,int y,int w,int ot,int id):t(t),x(x),y(y),w(w),ot(ot),id(id) {}
    bool operator < (const Node &b)const
    {
        if(x!=b.x)
            return x<b.x;
        if(y!=b.y)
            return y<b.y;
        return id<b.id;
    }
} q[N],tmp[N];

void CDQ(int l,int r)
{
    if(l==r)
        return;
    int mid=(l+r)>>1;
    for(int i=l; i<=r; ++i)
    {
        if(q[i].t<=mid&&q[i].ot==1)
            add(q[i].y,q[i].w);
        if(q[i].t>mid&&q[i].ot==2)
            ans[q[i].id]+=q[i].w*getsum(q[i].y);
    }
    for(int i=l; i<=r; ++i)
        if(q[i].t<=mid&&q[i].ot==1)
            add(q[i].y,-q[i].w);
    int t1=l-1,t2=mid;
    for(int i=l; i<=r; ++i)
        if(q[i].t<=mid)
            tmp[++t1]=q[i];
        else
            tmp[++t2]=q[i];
    for(int i=l; i<=r; ++i)
        q[i]=tmp[i];
    CDQ(l,mid);
    CDQ(mid+1,r);
}
LL FindValue(LL n,LL x,LL y)
{
    LL a,b,p,c,ans;
    p=(n+1)>>1;
    a=abs(x-p);
    b=abs(y-p);
    c=max(a,b);

    ans=(c*2-1)*(c*2-1);

    if(x==p+c)
    {
        ans+=(c*2)*3-1;
        ans+=y-(p-c);
        ans=n*n-ans;
        return ans;
    }
    else if(x==p-c)
    {
        ans+=c*2-1;
        ans+=(p+c)-y;
        return n*n-ans;
    }
    else if(y==p+c)
    {
        ans+=(p+c-1)-x;
        return n*n-ans;
    }
    else if(y==p-c)
    {
        ans+=c*4-1;
        ans+=x-(p-c);
        return n*n-ans;
    }
}
int cal(LL n,LL x,LL y)
{
    LL res=FindValue(n,x,y);
    int ret=0;
    while(res)
    {
        ret+=res%10;
        res/=10;
    }
    return ret;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        tim=0;
        int tot=0;
        int m,Q;
        scanf("%d%d%d",&n,&m,&Q);
        for(int i=1; i<=m; ++i)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int val=cal(n,x,y);
            q[++tot]=Node(++tim,x,y,val,1,0);
        }
        for(int i=1; i<=Q; ++i)
        {
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            ans[i]=0;//++tim1;
            q[++tot]=Node(++tim,x1-1,y1-1,+1,2,i);
            q[++tot]=Node(++tim,x2,y2,+1,2,i);
            q[++tot]=Node(++tim,x1-1,y2,-1,2,i);
            q[++tot]=Node(++tim,x2,y1-1,-1,2,i);
        }
        sort(q+1,q+tot+1);
        CDQ(1,tot);
        for(int i=1; i<=Q; ++i)
            printf("%d\n",ans[i]);
    }

    return 0;
}

主席树在线

https://blog.csdn.net/Endeavor_G/article/details/100188848

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值