HDU 6089 Rikka with Terrorist (线段树)

Posted suncongbo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6089 Rikka with Terrorist (线段树)相关的知识,希望对你有一定的参考价值。

题目链接

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 (线段树)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5634 Rikka with Phi

hdu 6090 Rikka with Graph

HDU 6095: Rikka with Competition

图论(生成树):HDU 5631Rikka with Graph

HDU 5631 Rikka with Graph

HDU6094 Rikka with K-Match