2019hdu暑假多校训练赛第九场1002 Rikka with Cake hdu6681(树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6681

题意:给定一个n*m的蛋糕,再给出K个操作,每次都是从蛋糕的中间向四个方向中的一个切过去,问最后蛋糕被切成多少块。

数据范围:1≤T≤100,1≤n,m≤109,1≤K≤105,1≤xi<n,1≤yi<m,Di∈{'L','R','U','D'}

 

思路:我们发现切的蛋糕块数正好等于交点的个数+1,那么这道题就转换成求交点个数的题了,首先离散化,然后给定的向上和向右的操作按照x递增排序,开始对y边插入(先插入比向上的x小的)边访问建立树状数组。其余四种情况相同的方法处理就好(向下和向右,向上和向左,向下和向左)。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,t,k,tot=0;
int xx[N],yy[N];
struct p{
    int x,y,qx,qy;
}a1[N],a2[N],a3[N],a4[N];
struct BIT{
    ll tree[N];
    void init(int k){
        for(int i=1;i<=k;i++)tree[i]=0;
    }
    void update(int x,ll val){
        while(x<=k){
            tree[x]+=val;
            x+=x&-x;
        }
    }
    ll getsum(int x){
        ll ans=0;
        while(x){
            ans+=tree[x];
            x-=x&-x;
        }
        return ans;
    }
}bit[5];
bool cmp1(p aa,p bb){
    return aa.x<bb.x;
}
bool cmp2(p aa,p bb){
    return aa.x>bb.x;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=4;i++)bit[i].init(k+5);
        int x,y;
        char s[5];
        int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
        for(int i=1;i<=k;i++){
            scanf("%d%d%s",&x,&y,s);
            if(s[0]=='U')a1[++cnt1].x=x,a1[cnt1].y=y;
            else if(s[0]=='L')a2[++cnt2].x=x,a2[cnt2].y=y;
            else if(s[0]=='R')a3[++cnt3].x=x,a3[cnt3].y=y;
            else if(s[0]=='D')a4[++cnt4].x=x,a4[cnt4].y=y;
            xx[i]=x,yy[i]=y;
        }
        sort(xx+1,xx+k+1);
        sort(yy+1,yy+k+1);
        for(int i=1;i<=cnt1;i++){
            a1[i].qx=lower_bound(xx+1,xx+k+1,a1[i].x)-xx;
            a1[i].qy=lower_bound(yy+1,yy+k+1,a1[i].y)-yy;
        }
        for(int i=1;i<=cnt2;i++){
            a2[i].qx=lower_bound(xx+1,xx+k+1,a2[i].x)-xx;
            a2[i].qy=lower_bound(yy+1,yy+k+1,a2[i].y)-yy;
        }
        for(int i=1;i<=cnt3;i++){
            a3[i].qx=lower_bound(xx+1,xx+k+1,a3[i].x)-xx;
            a3[i].qy=lower_bound(yy+1,yy+k+1,a3[i].y)-yy;
        }
        for(int i=1;i<=cnt4;i++){
            a4[i].qx=lower_bound(xx+1,xx+k+1,a4[i].x)-xx;
            a4[i].qy=lower_bound(yy+1,yy+k+1,a4[i].y)-yy;
        }
        sort(a1+1,a1+cnt1+1,cmp1);
        sort(a3+1,a3+cnt3+1,cmp1);
        sort(a4+1,a4+cnt4+1,cmp1);
        int ji=1;
        ll ans=0;
        for(int i=1;i<=cnt1;i++){
            for(int j=ji;j<=cnt3;j++){
                if(a3[j].qx<=a1[i].qx){
                    bit[1].update(k+1-a3[j].qy,1);
                    ji=j+1;
                }
                else break;
            }
            ans+=bit[1].getsum(k+1-a1[i].qy);
        }
        ji=1;
        for(int i=1;i<=cnt4;i++){
            for(int j=ji;j<=cnt3;j++){
                if(a3[j].qx<=a4[i].qx){
                    bit[2].update(a3[j].qy,1);
                    ji=j+1;
                }
                else break;
            }
            ans+=bit[2].getsum(a4[i].qy);
        }
        sort(a1+1,a1+cnt1+1,cmp2);
        sort(a2+1,a2+cnt2+1,cmp2);
        sort(a4+1,a4+cnt4+1,cmp2);
        ji=1;
        for(int i=1;i<=cnt1;i++){
            for(int j=ji;j<=cnt2;j++){
                if(a2[j].qx>=a1[i].qx){
                    bit[3].update(k+1-a2[j].qy,1);
                    ji=j+1;
                }
                else break;
            }
            ans+=bit[3].getsum(k+1-a1[i].qy);
        }
        ji=1;
        for(int i=1;i<=cnt4;i++){
            for(int j=ji;j<=cnt2;j++){
                if(a2[j].qx>=a4[i].qx){
                    bit[4].update(a2[j].qy,1);
                    ji=j+1;
                }
                else break;
            }
            ans+=bit[4].getsum(a4[i].qy);
        }
        printf("%lld\n",ans+1);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值