hdu4819_Mosaic_二维线段树(及二维线段树的概念的理解)

Mosaic

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)
Total Submission(s): 1745    Accepted Submission(s): 769


Problem Description
The God of sheep decides to pixelate some pictures (i.e., change them into pictures with mosaic). Here's how he is gonna make it: for each picture, he divides the picture into n x n cells, where each cell is assigned a color value. Then he chooses a cell, and checks the color values in the L x L region whose center is at this specific cell. Assuming the maximum and minimum color values in the region is A and B respectively, he will replace the color value in the chosen cell with floor((A + B) / 2).

Can you help the God of sheep?
 

Input
The first line contains an integer T (T ≤ 5) indicating the number of test cases. Then T test cases follow.

Each test case begins with an integer n (5 < n < 800). Then the following n rows describe the picture to pixelate, where each row has n integers representing the original color values. The j-th integer in the i-th row is the color value of cell (i, j) of the picture. Color values are nonnegative integers and will not exceed 1,000,000,000 (10^9).

After the description of the picture, there is an integer Q (Q ≤ 100000 (10^5)), indicating the number of mosaics.

Then Q actions follow: the i-th row gives the i-th replacement made by the God of sheep: xi, yi, Li (1 ≤ xi, yi ≤ n, 1 ≤ Li < 10000, Li is odd). This means the God of sheep will change the color value in (xi, yi) (located at row xi and column yi) according to the Li x Li region as described above. For example, an query (2, 3, 3) means changing the color value of the cell at the second row and the third column according to region (1, 2) (1, 3), (1, 4), (2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4). Notice that if the region is not entirely inside the picture, only cells that are both in the region and the picture are considered.

Note that the God of sheep will do the replacement one by one in the order given in the input.
 

Output
For each test case, print a line "Case #t:"(without quotes, t means the index of the test case) at the beginning.

For each action, print the new color value of the updated cell.
 

Sample Input
 
   
1 3 1 2 3 4 5 6 7 8 9 5 2 2 1 3 2 3 1 1 3 1 2 3 2 2 3
 

Sample Output
 
   
Case #1: 5 6 3 4 6
 
题意:给你一个矩阵,给你一个中心点(xi,yi),以中心点开始边长为Li的区域里最大值和最小值的平均值,且用平均值更新这个中心点。

解:二维线段树用就行了,看了学长的代码学习了二维线段树,扣了好久的说。

#include 
#include 
#include 
#include 
#include 

using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=810;
int num1[maxn][maxn],num[maxn<<2][maxn<<2],mxx[maxn<<2][maxn<<2],mnn[maxn<<2][maxn<<2];
int max1,min1,n,m;
void pushup(int nodex,int nodey){
    mxx[nodex][nodey]=max(mxx[nodex][nodey<<1],mxx[nodex][nodey<<1|1]);
    mnn[nodex][nodey]=min(mnn[nodex][nodey<<1],mnn[nodex][nodey<<1|1]);
}
void buildy(int l,int r,int x,int nodex,int nodey)//构建y方向的树
{
    if(l==r){                      //找到y树上确定的点
        if(x!=-1)
        mxx[nodex][nodey]=mnn[nodex][nodey]=num1[x][l];
        else{
        mxx[nodex][nodey]=max(mxx[nodex<<1][nodey],mxx[nodex<<1|1][nodey]);
        mnn[nodex][nodey]=min(mnn[nodex<<1][nodey],mnn[nodex<<1|1][nodey]);
        }
    return ;
    }
    int mid=(l+r)/2;
    buildy(l,mid,x,nodex,nodey<<1);
    buildy(mid+1,r,x,nodex,nodey<<1|1);
    pushup(nodex,nodey);
}
void buildx(int l,int r,int nodex)//开始构建x方向的树
{
    if(l==r){                 //找到确定的x树上的确定的点
        buildy(1,n,l,nodex,1);//在x树中进行y树的构建
        return ;
    }
    int mid=(l+r)/2;
    buildx(l,mid,nodex<<1);
    buildx(mid+1,r,nodex<<1|1);
    buildy(1,n,-1,nodex,1);//关键的地方:看了好久...这个地方的作用是求整个矩阵的最大和最小值;一层层的求取的是以x树为分割的区域块的最大和最小值;
}
void updatey(int l,int r,int b,int x,int val,int nodex,int nodey)
{
    if(l==r){
        if(x!=-1)
        mxx[nodex][nodey]=mnn[nodex][nodey]=val;
        else
        {
            mxx[nodex][nodey]=max(mxx[nodex<<1][nodey],mxx[nodex<<1|1][nodey]);
            mnn[nodex][nodey]=min(mnn[nodex<<1][nodey],mnn[nodex<<1|1][nodey]);
        }
        return ;
    }
    int mid = (l+r)/2;
    if(b<=mid){
    updatey(l,mid,b,x,val,nodex,nodey<<1);
    }
    else
    updatey(mid+1,r,b,x,val,nodex,nodey<<1|1);
    pushup(nodex,nodey);
}
void updatex(int l,int r,int x,int y,int val,int nodex)
{
    if(l==r)
    {
        updatey(1,n,y,l,val,nodex,1);
        return ;
    }
    int mid=(l+r)/2;
    if(x<=mid)updatex(l,mid,x,y,val,nodex<<1);
    else updatex(mid+1,r,x,y,val,nodex<<1|1);
    updatey(1,n,y,-1,val,nodex,1);

}
void queryy(int l,int r,int b,int d,int nodex,int nodey)
{
    if(b<=l&&r<=d)
    {
        max1=max(max1,mxx[nodex][nodey]);
        min1=min(min1,mnn[nodex][nodey]);
        return ;
    }
    int mid=(l+r)/2;
    if(b<=mid)queryy(l,mid,b,d,nodex,nodey<<1);
    if (d>mid)queryy(mid+1,r,b,d,nodex,nodey<<1|1);

}
void queryx(int a,int b,int c,int d,int l,int r,int nodex)
{
    if(a<=l&&c>=r)
    {
        queryy(1,n,b,d,nodex,1);
        return;
    }
    int mid=(l+r)/2;
    if(a<=mid)
    queryx(a,b,c,d,l,mid,nodex<<1);
    if(c>mid)queryx(a,b,c,d,mid+1,r,nodex<<1|1);
}
int main()
{
    int t;int count=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&num1[i][j]);
            }
        buildx(1,n,1);
        int xl,xr,yl,yr ;
        int a,b,c,d;
        scanf("%d",&m);

        printf("Case #%d:\n",++count);
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            max1=-INF,min1=INF;
            d=(c+1)/2;xl=a-d+1;xr=a+d-1;//定义查询区域的边长范围
            yl=b-d+1;yr=b+d-1;
            if(xl<1)xl=1;
            if(xr>n)xr=n;
            if(yl<1)yl=1;
            if(yr>n)yr=n;
            //cout<<"kkkkk"<

/ * 没什么好说的,二维线段树和一维的线段树一样,不过事树中套树的概念,例如一个x轴,y轴方向的矩阵,二维线段树就是先线段树x轴方向,确定了要找到的x轴后

再对x轴中的第x行进行线段树的构建,相当于是把矩阵先拆成一行一行,再分别对每一行进行一维线段树的构建,如此,查询和更新也就如是了*/


你可能感兴趣的:(线段树)