题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=6089

题解

这波强行维护搞得我很懵逼。。。
扫描线,只考虑每个点能走到左上方(不包括正上方,但包括正左方)的哪些点,然后旋转四次坐标系处理
所有询问和操作点按照先\(x\)\(y\)坐标的顺序排序,然后枚举每一行,按\(y\)从小到大的顺序枚举这一行每个点
对于一个询问点找出前面最后一个操作点,那么要求的就是一个矩形减去一个区间内所有后缀最大值的和
然后这个东西可以用线段树直接维护,记录个区间最大值然后pushup的时候二分
操作点就相当于单点修改
时间复杂度\(O(n\log^2n)\).

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<utility>
#include<algorithm>
#define llong long long
#define pll pair<llong,llong>
#define mkpr make_pair
using namespace std;
 
const int N = 1e5;
 
struct SegmentTree
{
    struct SgTNode
    {
        llong maxi,psum;
    } sgt[(N<<2)+3];
    void clear(int u,int le,int ri)
    {
        sgt[u].maxi = sgt[u].psum = 0;
        if(le==ri) return;
        int mid = (le+ri)>>1;
        clear(u<<1,le,mid); clear(u<<1|1,mid+1,ri);
    }
    llong calc(int u,int le,int ri,llong x)
    {
        if(le==ri) {return sgt[u].maxi<x ? x : sgt[u].maxi;}
        int mid = (le+ri)>>1;
        if(sgt[u<<1|1].maxi<x) {return calc(u<<1,le,mid,x)+x*(ri-mid);}
        else {return sgt[u].psum-sgt[u<<1|1].psum+calc(u<<1|1,mid+1,ri,x);} //Note here!
    }
    void pushup(int u,int le,int ri)
    {
        int mid = (le+ri)>>1;
        sgt[u].maxi = max(sgt[u<<1].maxi,sgt[u<<1|1].maxi);
        sgt[u].psum = calc(u<<1,le,mid,sgt[u<<1|1].maxi)+sgt[u<<1|1].psum;
    }
    void modify(int u,int le,int ri,int pos,llong x)
    {
        if(le==pos && ri==pos) {sgt[u].maxi = sgt[u].psum = x; return;}
        int mid = (le+ri)>>1;
        if(pos<=mid) {modify(u<<1,le,mid,pos,x);}
        else {modify(u<<1|1,mid+1,ri,pos,x);}
        pushup(u,le,ri);
    }
    pll query(int u,int le,int ri,int lb,int rb,llong x)
    {
        if(lb>rb) {return make_pair(0,0);}
        if(le>=lb && ri<=rb) {return make_pair(max(sgt[u].maxi,x),calc(u,le,ri,x));}
        int mid = (le+ri)>>1;
        if(rb<=mid) {return query(u<<1,le,mid,lb,rb,x);}
        else if(lb>mid) {return query(u<<1|1,mid+1,ri,lb,rb,x);}
        else
        {
            pll retr = query(u<<1|1,mid+1,ri,lb,rb,x);
            pll retl = query(u<<1,le,mid,lb,rb,retr.first);
            return mkpr(retl.first,retl.second+retr.second);
        }
    }
} sgt;
 
struct Query
{
    int x,y,id;
    Query() {}
    Query(int _x,int _y,int _id) {x = _x,y = _y,id = _id;}
    bool operator <(const Query &arg) const
    {
        return x<arg.x || (x==arg.x && y<arg.y);
    }
};
llong fans[N+3];
int mx[N+3];
 
namespace Solve
{
    Query qr[(N<<1)+3];
    int q;
    int nx,ny;
    void addquery(int x,int y,int id) {q++; qr[q] = Query(x,y,id);}
    void solve()
    {
        sort(qr+1,qr+q+1); int j = 1; while(j<=q && qr[j].x==0) j++;
        for(int i=1; i<=nx; i++)
        {
            int k = 0;
            while(j<=q && qr[j].x==i)
            {
                if(qr[j].id==0)
                {
                    sgt.modify(1,1,ny,qr[j].y,i);
                    k = qr[j].y; mx[qr[j].y] = i;
                }
                else
                {
                    llong ans = (llong)i*(qr[j].y-1-k)-sgt.query(1,1,ny,k+1,qr[j].y-1,mx[qr[j].y]).second; //Note here!
                    fans[qr[j].id] += ans;
                }
                j++;
            }
        }
        q = 0; sgt.clear(1,1,ny); for(int i=1; i<=ny; i++) mx[i] = 0ll;
    }
}
 
Query a[N+3],b[N+3];
int nx,ny,m,q;
 
int main()
{
	int T; scanf("%d",&T);
	while(T--)
	{
	    scanf("%d%d%d%d",&nx,&ny,&m,&q);
	    for(int i=1; i<=m; i++) scanf("%d%d",&a[i].x,&a[i].y);
	    for(int i=1; i<=q; i++) scanf("%d%d",&b[i].x,&b[i].y);
	    //1
	    Solve::nx = nx; Solve::ny = ny;
	    for(int i=1; i<=m; i++) Solve::addquery(a[i].x,a[i].y,0);
	    for(int i=1; i<=q; i++) Solve::addquery(b[i].x,b[i].y,i);
	    Solve::solve();
	    //2
	    Solve::nx = ny; Solve::ny = nx;
	    for(int i=1; i<=m; i++) Solve::addquery(a[i].y,nx+1-a[i].x,0);
	    for(int i=1; i<=q; i++) Solve::addquery(b[i].y,nx+1-b[i].x,i);
	    Solve::solve();
	    //3
	    Solve::nx = nx; Solve::ny = ny;
	    for(int i=1; i<=m; i++) Solve::addquery(nx+1-a[i].x,ny+1-a[i].y,0);
	    for(int i=1; i<=q; i++) Solve::addquery(nx+1-b[i].x,ny+1-b[i].y,i);
	    Solve::solve();
	    //4
	    Solve::nx = ny; Solve::ny = nx;
	    for(int i=1; i<=m; i++) Solve::addquery(ny+1-a[i].y,a[i].x,0);
	    for(int i=1; i<=q; i++) Solve::addquery(ny+1-b[i].y,b[i].x,i);
	    Solve::solve();
	    for(int i=1; i<=q; i++) printf("%lld\n",fans[i]+1);
	    memset(fans,0,sizeof(fans));
	}
    return 0;
}