hdu6681 Rikka with Cake(主席树)

题目链接
大意:给你一个矩形区域, ( ( 0 , 0 ) ( n , m ) ) ((0,0)-(n,m)) ((0,0)(n,m)),现在有k条直线,每条直线都是从一个点出发到上下左右四个方向之一。
问你这个区域被分成了多少块。
思路:稍微观察即可发现,分成的区域等于直线交点个数+1。
我们对 L , R L,R L,R方向的对纵坐标分开离散化建立主席树(横坐标放一起离散化),然后每次遍历 U , D U,D U,D方向的直线来在主席树上查询。
设当前横坐标为x
方向是U的话,那么L方向上横坐标x大于等于x的都为有效贡献,小于等于x的R方向都有贡献(纵坐标在范围内)。
方向的D的话,那么L方向上横坐标x大于等于x的都为有效贡献,小于等于x的R方向都有贡献(纵坐标在范围内)。
我们查询的时候分别对两个主席树进行查询,每次查询一个合法的纵坐标区间即可。
细节见代码

#include<bits/stdc++.h>

#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back

using namespace std;

LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL powmod(LL a,LL b,LL MOD){LL ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
const int N = 3e5 +11;
int t;
int n,m,k;
struct uzi
{
    int a,b;
    char c;
}p[N];
int a[N],b[N];
char c[N];
int cmp(uzi l,uzi r){
    return l.b<r.b;
}
struct fak{
    LL sum;
    int l,r;    
}T1[N*40],T2[N*40];
int n1,n2;
int t1[N],t2[N];
void up1(int l,int r,int &x,int y,int pos){
    T1[++n1]=T1[y];if(pos)T1[n1].sum++;x=n1;
    if(l==r)return ;
    int mid=l+r>>1;
    if(mid>=pos)up1(l,mid,T1[x].l,T1[y].l,pos);
    else up1(mid+1,r,T1[x].r,T1[y].r,pos);
}
void up2(int l,int r,int &x,int y,int pos){
    T2[++n2]=T2[y];if(pos)T2[n2].sum++;x=n2;
    if(l==r)return ;
    int mid=l+r>>1;
    if(mid>=pos)up2(l,mid,T2[x].l,T2[y].l,pos);
    else up2(mid+1,r,T2[x].r,T2[y].r,pos);
}
LL g1(int l,int r,int x,int y,int k){
    if(!x&&!y)return 0;
    if(r<k)return 0;
    if(l>=k)return T1[y].sum-T1[x].sum;;
    int mid=l+r>>1;
    return g1(l,mid,T1[x].l,T1[y].l,k)+g1(mid+1,r,T1[x].r,T1[y].r,k);
}
LL g2(int l,int r,int x,int y,int k){
    if(!x&&!y)return 0;
    if(l>k)return 0;
    if(r<=k)return (T2[y].sum-T2[x].sum);
    int mid=l+r>>1;
    return g2(l,mid,T2[x].l,T2[y].l,k)+g2(mid+1,r,T2[x].r,T2[y].r,k);
}
int PA[N],PB[N],La,Lb;
int main(){
    ios::sync_with_stdio(false);
    for(cin>>t;t;t--){
        cin>>n>>m>>k;
        n1=n2=0;
        La=0;Lb=0;
        for(int i=1;i<=k;i++){
            cin>>a[i]>>b[i]>>c[i];
            p[i]={a[i],b[i],c[i]};
            if(c[i]=='L')PA[++La]=b[i];
            if(c[i]=='R')PB[++Lb]=b[i];
        }
        sort(a+1,a+1+k);
        int r=unique(a+1,a+1+k)-a-1;
        sort(PA+1,PA+1+La);
        sort(PB+1,PB+1+Lb);
        La=unique(PA+1,PA+1+La)-PA-1;
        Lb=unique(PB+1,PB+1+Lb)-PB-1;
        for(int i=1;i<=k;i++){
            if(c[i]=='L'){
                p[i].b=lower_bound(PA+1,PA+1+La,p[i].b)-PA;
            }else if(c[i]=='R'){
                p[i].b=lower_bound(PB+1,PB+1+Lb,p[i].b)-PB;
            }
        }
        for(int i=1;i<=k;i++)p[i].a=lower_bound(a+1,a+1+r,p[i].a)-a;
        sort(p+1,p+1+k,cmp);
        for(int i=1;i<=k;i++){
            if(p[i].c=='L'){
                up1(0,r+1,t1[p[i].b],t1[p[i].b-1],p[i].a);
            }else if(p[i].c=='R'){
                up2(0,r+1,t2[p[i].b],t2[p[i].b-1],p[i].a);
            }
        }
        up1(0,r+1,t1[La+1],t1[La],0);
        up2(0,r+1,t2[Lb+1],t2[Lb],0);
        LL A=0;
        for(int i=1;i<=k;i++){
            if(p[i].c=='U'){
                int quL=lower_bound(PA+1,PA+1+La,p[i].b)-PA;
                int quR=lower_bound(PB+1,PB+1+Lb,p[i].b)-PB;
                A+=g1(0,r+1,t1[quL-1],t1[La+1],p[i].a);
                A+=g2(0,r+1,t2[quR-1],t2[Lb+1],p[i].a);
            }else if(p[i].c=='D'){
                int quL=upper_bound(PA+1,PA+1+La,p[i].b)-PA;
                int quR=upper_bound(PB+1,PB+1+Lb,p[i].b)-PB;    
                quL--;
                quR--;
                A+=g1(0,r+1,0,t1[quL],p[i].a);
                A+=g2(0,r+1,0,t2[quR],p[i].a);
            }
        }
        cout<<A+1<<endl;
    }
    return 0;
}
全部评论

相关推荐

有趣的牛油果开挂了:最近这个阶段收到些杂七杂八的短信是真的烦
点赞 评论 收藏
分享
10-30 22:18
已编辑
毛坦厂中学 C++
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务