1. 程式人生 > >codeforces 853c (關於矩形的主席樹)

codeforces 853c (關於矩形的主席樹)

Ilya is sitting in a waiting area of Metropolis airport and is bored of looking at time table that shows again and again that his plane is delayed. So he took out a sheet of paper and decided to solve some problems.

First Ilya has drawn a grid of size n × n and marked n squares on it, such that no two marked squares share the same row or the same column. He calls a rectangle on a grid with sides parallel to grid sides beautiful if exactly two of its corner squares are marked. There are exactly n·(n - 1) / 2 beautiful rectangles.

Ilya has chosen q query rectangles on a grid with sides parallel to grid sides (not necessarily beautiful ones), and for each of those rectangles he wants to find its beauty degree. Beauty degree of a rectangle is the number of beautiful rectangles that share at least one square with the given one.

Now Ilya thinks that he might not have enough time to solve the problem till the departure of his flight. You are given the description of marked cells and the query rectangles, help Ilya find the beauty degree of each of the query rectangles.

Input
The first line of input contains two integers n and q (2 ≤ n ≤ 200 000, 1 ≤ q ≤ 200 000) — the size of the grid and the number of query rectangles.

The second line contains n integers p1, p2, …, pn, separated by spaces (1 ≤ pi ≤ n, all pi are different), they specify grid squares marked by Ilya: in column i he has marked a square at row pi, rows are numbered from 1 to n, bottom to top, columns are numbered from 1 to n, left to right.

The following q lines describe query rectangles. Each rectangle is described by four integers: l, d, r, u (1 ≤ l ≤ r ≤ n, 1 ≤ d ≤ u ≤ n), here l and r are the leftmost and the rightmost columns of the rectangle, d and u the bottommost and the topmost rows of the rectangle.

Output
For each query rectangle output its beauty degree on a separate line.

Example
Input
2 3
1 2
1 1 1 1
1 1 1 2
1 1 2 2
Output
1
1
1
Input
4 2
1 3 2 4
4 1 4 4
1 1 2 3
Output
3
5
Note
The first sample test has one beautiful rectangle that occupies the whole grid, therefore the answer to any query is 1.

In the second sample test the first query rectangle intersects 3 beautiful rectangles, as shown on the picture below:

There are 5 beautiful rectangles that intersect the second query rectangle, as shown on the following picture:

題意

一個n*n的格子,每一行和每一列都有且只有一個黑色格子。“美麗的矩形”定義為一個矩形的四個角中恰好有兩個是黑色格子。
對於每次詢問,給出一個矩形,查詢至少包含給定矩形的一個格子的所有矩形中,“美麗的矩形”的個數。
(不懂的可以看Codeforces853C樣例解釋)。

解題思路

假設在n*n的區域中給出一個矩形,那麼區域會被劃分成以下9塊,其中第5塊表示給定矩形

1 2 3
4 5 6
7 8 9
假定我們用主席樹求出了9塊中每一塊裡面包含的黑色格子的個數,第i塊內的黑色格子數目記為cnti。
對9塊中每一塊分別考慮。
對第1塊而言,能和它組成“美麗的矩形”並符合要求的黑色格子一定在第5/6/8/9塊中。
對第2塊而言,能和它組成“美麗的矩形”並符合要求的黑色格子一定在第4/5/6/7/8/9塊中。
……
對第5塊而言,能和它組成“美麗的矩形”並符合要求的黑色格子一定是所有黑色格子,也就是(n-1)個格子。
……
假設我們把這些答案累加起來,會發現每個“美麗的矩形”被算了兩次,因此答案需要/2。

大佬講得很好啊。。。。對啊。。其實仔細一看 它就是一個序列而已
2e5 要開到 *21

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int ls[200013*21],rs[200013*21];
int sum[200013*21];
int root[200100];
int tot=0;

void pushup(int now)
{
    sum[now]=sum[ls[now]]+sum[rs[now]];
}


void update(int pre,int &now ,int l,int r,int d)
{
    now=++tot;
    ls[now]=ls[pre];
    rs[now]=rs[pre];
    sum[now]=sum[pre];
    if(l==r&&l==d)
    {
        sum[now]++;
        return ;
    }
    int mid=(l+r)>>1;
    if(d<=mid) update(ls[pre],ls[now],l,mid,d);
    else update(rs[pre],rs[now],mid+1,r,d);
    pushup(now);
}


int query(int l1,int r1,int L,int R,int l,int r)
{
    if(L<=l&&R>=r)
        return (sum[r1]-sum[l1]);
    int re=0;
    int mid=(l+r)>>1;
    if(L<=mid) re+=query(ls[l1],ls[r1],L,R,l,mid);
    if(R>mid) re+=query(rs[l1],rs[r1],L,R,mid+1,r);
    return re;
}

int build(int l,int r)
{
    int rot=++tot;
    sum[rot]=0;
    if(l==r)
        return rot;
    int mid=(l+r)>>1;
    ls[rot]=build(l,mid);
    rs[rot]=build(mid+1,r);
    return rot;
}

int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    root[0]=build(1,n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        update(root[i-1],root[i],1,n,x);
    }
    while(q--)
    {
        int l,d,r,u;
        int sum1=0,sum2=0,sum3=0,sum4=0,sum5=0,sum6=0,sum7=0,sum8=0,sum9=0;
        scanf("%d%d%d%d",&l,&d,&r,&u);
        if(d-1>=1)
        {
            sum1=query(root[0],root[l-1],1,d-1,1,n);
            sum2=query(root[l-1],root[r],1,d-1,1,n);
            sum3=query(root[r],root[n],1,d-1,1,n);
        }
        sum4=query(root[0],root[l-1],d,u,1,n);
        sum5=query(root[l-1],root[r],d,u,1,n);
        sum6=query(root[r],root[n],d,u,1,n);

        sum7=query(root[0],root[l-1],u+1,n,1,n);
        sum8=query(root[l-1],root[r],u+1,n,1,n);
        sum9=query(root[r],root[n],u+1,n,1,n);
        // cout<<sum1<<" "<<sum2<<" "<<sum3<<" "<<sum4<<" "<<sum5<<" "<<sum6<<" "
        // <<sum7<<" "<<sum8<<" "<<sum9<<endl;
        ll res=1ll*sum1*(1ll*sum5+sum6+sum8+sum9);
        res+=1ll*sum2*(1ll*sum4+sum5+sum6+sum7+sum8+sum9);
        res+=1ll*sum3*(1ll*sum4+sum5+sum7+sum8);
        res+=1ll*sum4*(1ll*sum2+sum3+sum5+sum6+sum8+sum9);
        res+=1ll*sum5*(n-1);
        res+=1ll*sum6*(1ll*sum2+sum1+sum4+sum5+sum7+sum8);
        res+=1ll*sum7*(1ll*sum2+sum3+sum5+sum6);
        res+=1ll*sum8*(1ll*sum1+sum2+sum3+sum4+sum5+sum6);
        res+=1ll*sum9*(1ll*sum1+sum2+sum4+sum5);
        printf("%lld\n",res/2 );
    }
}