FZU 2225 小茗的魔法阵 扫描线+树状数组

这个题和一个CF上的找"Z"的题差不多,都是扫描线+树状数组

从右上角的主对角线开始扫描,一直扫到左下角,每次更新,右延伸等于该扫描线的点,注意在其所在的树状数组更新就好了

时间复杂度O(n^2logn)

#include <stdio.h>
#include <iostream>
#include <vector>
#include <math.h>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <string.h>
#include <string>
using namespace std;
typedef long long LL;
const LL mod=1e8+7;
const int N=1e3+5;
int c[2005][N],n,m;
char s[N][N];
int r[N][N],xl[N][N],xr[N][N];
struct Point
{
    int x,y;
};
vector<Point>g[2005];
void add(int pos,int x)
{
    for(int i=x; i<=m; i+=i&(-i))
        ++c[pos][i];
}
int sum(int pos,int x)
{
    int ans=0;
    if(x==0)return 0;
    for(int i=x; i>0; i-=i&(-i))
        ans+=c[pos][i];
    return ans;
}
int main()
{
    int T,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n+m; ++i)g[i].clear();
        for(int i=1; i<=n; ++i)scanf("%s",s[i]+1);
        memset(xl,0,sizeof(xl));
        memset(xr,0,sizeof(xr));
        memset(r,0,sizeof(r));
        memset(c,0,sizeof(c));
        for(int j=m; j>0; --j)
            for(int i=1; i<=n; ++i)
                if(s[i][j]=='x')r[i][j]=r[i][j+1]+1;
        for(int i=n; i>0; --i)
            for(int j=1; j<=m; ++j)
                if(s[i][j]=='x')xl[i][j]=xl[i+1][j-1]+1,xr[i][j]=xr[i+1][j+1]+1;
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=m; ++j)
                if(s[i][j]=='x')
                {
                    int x=i,y=j+r[i][j]-1;
                    if(x<y)y-=(x-1),x=1;
                    else x-=(y-1),y=1;
                    Point tmp;
                    tmp.x=i,tmp.y=j;
                    int id;
                    if(x==1)id=y;
                    else id=m+x;
                    g[id].push_back(tmp);
                }
        int res=0;
        for(int i=m; i>=1; --i)
        {
            for(int j=0; j<g[i].size(); ++j)
            {
                int pos=g[i][j].x+g[i][j].y;
                add(pos,g[i][j].y);
            }
            for(int x=1,y=i; x<=n&&y<=m; ++x,++y)
            {
                if(s[x][y]!='x')continue;
                int l=min(xl[x][y],xr[x][y]);
                res+=sum(x+y,y)-sum(x+y,y-l);
            }
        }
        for(int i=2; i<=n; ++i)
        {
            for(int j=0; j<g[m+i].size(); ++j)
            {
                int pos=g[i+m][j].x+g[i+m][j].y;
                add(pos,g[i+m][j].y);
            }
            for(int x=i,y=1; x<=n&&y<=m; ++x,++y)
            {
                if(s[x][y]!='x')continue;
                int l=min(xl[x][y],xr[x][y]);
                res+=sum(x+y,y)-sum(x+y,y-l);
            }
        }
        printf("Case #%d: %d
",++cas,res);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/shuguangzw/p/5400455.html