码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 6089 Rikka with Terrorist (线段树)

时间:2019-08-06 13:55:05      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:线段   line   shu   nod   直接   ==   query   pair   operator   

题目链接

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;
}

HDU 6089 Rikka with Terrorist (线段树)

标签:线段   line   shu   nod   直接   ==   query   pair   operator   

原文地址:https://www.cnblogs.com/suncongbo/p/11308252.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!