hdu 6238 Rectangle Radar Scanner 分治

Problem J. Rectangle Radar Scanner
Time Limit: 20000/15000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 422 Accepted Submission(s): 142

Problem Description
There are n houses on the ground, labeled by 1 to n. The i-th house is located at (i,yi), and there is a spy transmitter with energy wi inside the i-th house.
Little Q has a rectangle radar scanner, which can find all the transmitters within the range [xl,xr]×[yl,yr]. That means a transmitter located at (x,y) can be found if xl≤x≤xr and yl≤y≤yr.
Your task is to achieve the scanner efficiently.
Given m queries xli,xri,yli,yri, for each query, please find all the transmitters within the range, then report the product of their energy and the maximum/minimum energy among them.
To reduce the large input, we will use the following generator. The numbers a0,b0,c0,d0,p,q,r and MOD are given initially. The values ai,bi,ci,di,xli,xri,yli,yri are then produced as follows :
aibicidixlixriyliyri========(p×ai−1+q×bi−1+r)modMOD(p×bi−1+q×ai−1+r)modMOD(p×ci−1+q×di−1+r)modMOD(p×di−1+q×ci−1+r)modMODmin(aimodn,bimodn)+1max(aimodn,bimodn)+1min(cimodn,dimodn)+1max(cimodn,dimodn)+1

Input
The first line of the input contains an integer T(1≤T≤3), denoting the number of test cases.
In each test case, there is an integer n(1≤n≤100000) in the first line, denoting the number of houses.
In the next n lines, each line contains 2 integers yi,wi(1≤yi≤n,1≤wi≤109), describing a house.
Then in the next line, there are 10 integers m,a0,b0,c0,d0,p,q,r,MOD,k, describing the queries. It is guaranteed that 1≤m≤106 and 5≤a0,b0,c0,d0,p,q,r,MOD,k≤109.

Output
Since the output file may be very large, let’s denote prodi as the product of of the i-th query, maxi as the maximum energy of the i-th query, and denote mini as the minimum energy of the i-th query. Note that when there are no avaliable transmitters, then prodi=maxi=mini=0.
For each test case, you need to print a single line containing an integer answer, where :
answer=∑i=1m((prodimodk)⊕maxi⊕mini)

Note that ``⊕’’ denotes binary XOR operation.

Sample Input
1
5
2 6
1 8
5 2
4 9
2 4
3 5 6 7 8 9 8 7 998244353 10007

Sample Output
68

Source
2018 Multi-University Training Contest 3

Recommend
chendu
题意:给出一个n*n的二维空间,上面有一些点,每个点有一个权值wi,给出m个矩形,问每个矩形里面的权值积,最大权值和最小权值。
做法:分治,先把问题转化一下,用 (xl,xr,yl,yr)表示矩形,如果有一些矩形的xl一样,那么把矩形按照xr从小到大排序,建立一棵线段树,线段树的点保存纵坐标上面的数的积,最大值,最小值。每次xr变化的时候就把上一个xr到这个xr之间的点填到线段树里面,然后因为xr是递增的,那么对于某个点来说有效的点是从xl到xr之间的点,纵坐标在yl到yr之间,对于某个矩形来说,它的结果可以用一个query来得到,复杂度是log的。
然后回到这一题,处理一个区间的时候,把越过区间中间点的矩形沿着中间点切成两半,那么处理两边的矩形就可以用上面的方法了。对两边分别用线段树跑一遍就好了。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;

struct node{int x,l,r,id;}nl[N],nr[N];
bool cmp1(node a,node b){return a.x > b.x;}
bool cmp2(node a,node b){return a.x < b.x;}
struct node2{int xl,xr,yl,yr,id;}qs[N],ts[N];
struct node3{int sum,mn,mx;}sum[N<<2];
int y[N],w[N];
int mul[N],mx[N],mn[N];
int mod;
int n,m;
void build(int l,int r,int rt){
    sum[rt].sum= 1;
    sum[rt].mx = 0;
    sum[rt].mn = 1e9;
    if(l == r) return ;
    int mid = l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
}

node3 pushup(node3 a,node3 b){
    a.sum= 1LL*a.sum*b.sum%mod;
    a.mx = max(a.mx,b.mx);
    a.mn = min(a.mn,b.mn);
    return a;
}

void update(int x,int d,int l,int r,int rt){
    if(l == r){
        sum[rt].sum = sum[rt].sum*1LL*d%mod;
        sum[rt].mx = max(sum[rt].mx,d);
        sum[rt].mn = min(sum[rt].mn,d);
        return ;
    }
    int mid = l+r>>1;
    if(mid >= x) update(x,d,l,mid,rt<<1);
    else update(x,d,mid+1,r,rt<<1|1);
    //pushup(rt);
    sum[rt] = pushup(sum[rt<<1],sum[rt<<1|1]);
}

void cle(int x,int l,int r,int rt){
    sum[rt].sum= 1;
    sum[rt].mn = 1e9;
    sum[rt].mx = 0;

    if(l == r) return;
    int mid = l+r>>1;
    if(mid >= x) cle(x,l,mid,rt<<1);
    else cle(x,mid+1,r,rt<<1|1);
}
node3 query(int L,int R,int l,int r,int rt){
    if(L <= l && R >= r){
        return sum[rt];
    }
    int  mid = l+r>>1;
//    node3 ret;
//    ret.sum = 1,ret.mx = 0,ret.mn = 1e9;
//    if(mid >= L) ret = pushup(ret,query(L,R,l,mid,rt<<1));
//    if(mid < R) ret = pushup(ret,query(L,R,mid+1,r,rt<<1|1));
    if(mid >= L&& mid < R) return pushup(query(L,R,l,mid,rt<<1),query(L,R,mid+1,r,rt<<1|1));
    if(mid >= L) return query(L,R,l,mid,rt<<1);
    if(mid < R) return query(L,R,mid+1,r,rt<<1|1);
}


void solve(int l,int r,int L,int R){

    if(l > r) return ;
    int mid = L+R>>1;
    int cl = 0,cr = 0,ll = l,lr = r;
    for(int i = l;i <= r;i ++){
        if(qs[i].xr < mid){ts[ll++] = qs[i];continue;}
        if(qs[i].xl > mid){ts[lr--] = qs[i];continue; }
        nl[cl++] = (node){qs[i].xl,qs[i].yl,qs[i].yr,qs[i].id};
        nr[cr++] = (node){qs[i].xr,qs[i].yl,qs[i].yr,qs[i].id};
    }
    sort(nl,nl+cl,cmp1);
    for(int i = 0,j = mid;i < cl;i ++){
        for(;j >= L && j >= nl[i].x;j --) {update(y[j],w[j],1,n,1);}
        node3 tmp= query(nl[i].l,nl[i].r,1,n,1);
        //cout <<tmp.sum << ' '<< tmp.mx << ' '<<tmp.mn<< endl;
        mul[nl[i].id] = mul[nl[i].id]*1ll*tmp.sum%mod;
        mx[nl[i].id] = max(mx[nl[i].id],tmp.mx);
        mn[nl[i].id] = min(mn[nl[i].id],tmp.mn);
    }
    for(int i = L;i <= mid;i ++) cle(y[i],1,n,1);
    sort(nr,nr+cr,cmp2);
    for(int i = 0,j = mid+1;i < cr;i ++){
        while(j <= R && j <= nr[i].x){
            update(y[j],w[j],1,n,1);
            //cout <<"!!" <<y[j] << ' '<<w[j] << endl;
            j++;
        }
        node3 tmp = query(nr[i].l,nr[i].r,1,n,1);
        //cout <<tmp.sum << ' '<< tmp.mx << ' '<<tmp.mn<< endl;
        mul[nr[i].id] = mul[nr[i].id]*1ll*tmp.sum%mod;
        mx[nr[i].id] = max(mx[nr[i].id],tmp.mx);
        mn[nr[i].id] = min(mn[nr[i].id],tmp.mn);
    }

    for(int i = mid;i <= R;i ++) cle(y[i],1,n,1);
    for(int i = l;i <= r;i ++) qs[i] = ts[i];
    solve(l,ll-1,L,mid-1);
    solve(lr+1,r,mid+1,R);
}




int main(){
    int T;
    cin >> T;
    while(T--){
        int ba,bb,bc,bd,p,q,r,mk;
        scanf("%d",&n);
        for(int i = 1;i <= n;i ++) scanf("%d %d",&y[i],&w[i]);
        scanf("%d",&m);
        scanf("%d %d %d %d %d %d %d %d %d",&ba,&bb,&bc,&bd,&p,&q,&r,&mod,&mk);
        for(int i = 1;i <= m;i ++) mul[i] = 1,mx[i] = 0,mn[i] = 1e9;
        for(int i = 1;i <= m;i ++){
            int a,b,c,d;
            a = (1LL*p*ba+1LL*q*bb+r)%mod;
            b = (1LL*p*bb+1LL*q*ba+r)%mod;
            c = (1LL*p*bc+1LL*q*bd+r)%mod;
            d = (1LL*p*bd+1LL*q*bc+r)%mod;
            qs[i].xl = min(a%n,b%n)+1;
            qs[i].xr = max(a%n,b%n)+1;
            qs[i].yl = min(c%n,d%n)+1;
            qs[i].yr = max(c%n,d%n)+1;
            //cout << qs[i].xl <<  ' '<<qs[i].xr << ' '<<qs[i].yl << ' ' << qs[i].yr << endl;
            qs[i].id = i;
            ba = a,bb = b,bc = c,bd = d;
        }
        mod = mk;
        build(1,n,1);
        solve(1,m,1,n);
        long long ans = 0;
        for(int i = 1;i <= m;i ++){
            //cout << i << ' '<<mul[i] << ' '<<mx[i] << ' '<<mn[i] << endl;
            if(mx[i]) ans += mul[i]^mx[i]^mn[i];
        }

        printf("%lld\n",ans);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值