hdu6089 Rikka with Terrorist

本文深入探讨了李超树的原理与应用,通过解决一个关于平面内安全点的复杂问题,展示了李超树在处理二维数点问题上的强大能力。文章详细介绍了李超树的实现过程,包括线段树的构建、折线维护、面积计算等关键步骤,并提供了完整的代码示例。
摘要由CSDN通过智能技术生成

题意:n*m的平面内有K个不安全点,Q个询问位置在(x,y)的人能走到多少个点?走到:(x,y)和(x',y')之间的矩形中不包含不安全点。

 

标程:

 1 #include<bits/stdc++.h>
 2 #define mid ((l+r)>>1)
 3 using namespace std;
 4 int read()
 5 {
 6    int x=0,f=1;char ch=getchar();
 7    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
 8    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
 9    return x*f;
10 }
11 const int N=100005;
12 typedef long long ll;
13 int n,m,K,Q,T_Max[N<<2],tot,Max;
14 ll ans[N],T_sum[N<<2],T_suml[N<<2];
15 struct node{int x,y,id,ty;node(){} node(int a,int b,int c,int d){x=a;y=b;id=c;ty=d;}}a[N*2],dg[N],q[N];
16 bool cmp(const node &A,const node &B) {return A.x<B.x||A.x==B.x&&A.y<B.y||A.x==B.x&&A.y==B.y&&A.ty<B.ty;}//排序时||不要写成&&! 
17 ll qry_sum(int k,int l,int r,int L,int R,int &mx)//表示当前区间的右边下界为mx时的折线下面积 
18 {
19     if (L<=l&&r<=R)
20     {
21         if (mx>=T_Max[k]) return (ll)mx*(r-l+1);   
22         if (l==r) return mx=T_Max[k]; 
23         int tt=T_Max[k<<1|1]; ll res=0;
24         if (mx>=tt)
25         {
26            res+=(ll)mx*(r-mid);//mx会被修改,注意统计顺序! 
27             res+=qry_sum(k<<1,l,mid,L,R,mx);
28         }else {
29             res+=T_suml[k];
30             res+=qry_sum(k<<1|1,mid+1,r,L,R,mx); 
31         }
32         mx=T_Max[k]; return res;
33     }
34     ll s=0;
35     if (R>mid) s+=qry_sum(k<<1|1,mid+1,r,L,R,mx);//先走右边,更新下界 
36     if (L<=mid) s+=qry_sum(k<<1,l,mid,L,R,mx);
37     return s;
38 }
39 void ins(int k,int l,int r,int x,int y)
40 {
41     if (l==r)
42     {
43         if (y>T_Max[k]) T_Max[k]=T_sum[k]=y;
44         return; 
45     }
46     if (x<=mid) ins(k<<1,l,mid,x,y);else ins(k<<1|1,mid+1,r,x,y);
47     int tt=T_Max[k<<1|1];
48     T_suml[k]=qry_sum(k<<1,l,mid,l,mid,tt);//注意如果直接传入T_Max[k<<1|1]的话,在&下会被修改。 
49     T_Max[k]=max(T_Max[k<<1],T_Max[k<<1|1]); 
50     T_sum[k]=T_suml[k]+T_sum[k<<1|1];
51 }
52 void work()
53 {
54     tot=0;
55     for (int i=1;i<=K;i++) a[++tot]=node(dg[i].x,dg[i].y,i,0);
56     for (int i=1;i<=Q;i++) a[++tot]=node(q[i].x,q[i].y,i,1);
57     sort(a+1,a+tot+1,cmp);
58     for (int i=1;i<=tot;i++)
59     {
60         if (!a[i].ty) ins(1,1,m,a[i].y,a[i].x);
61         else {
62             Max=0;ans[a[i].id]+=qry_sum(1,1,m,1,a[i].y,Max);//二维数点
63             Max=0;ans[a[i].id]-=qry_sum(1,1,m,a[i].y,a[i].y,Max);//减去重复的一条同行/同列轴 
64         }
65     }
66 } 
67 int main()
68 {
69     int T=read();
70     while (T--)
71     {
72        n=read();m=read();K=read();Q=read();
73        for (int i=1;i<=K;i++) dg[i].x=read(),dg[i].y=read();
74        for (int i=1;i<=Q;i++) q[i].x=read(),q[i].y=read(),ans[i]=0;//组测清零 
75         for (int i=0;i<4;i++)
76         {
77             work();
78             for (int i=1;i<=(m<<2);i++) T_sum[i]=T_suml[i]=T_Max[i]=0; 
79             for (int j=1;j<=K;j++) dg[j].x=n-dg[j].x+1,swap(dg[j].x,dg[j].y);//90度旋转坐标 
80             for (int j=1;j<=Q;j++) q[j].x=n-q[j].x+1,swap(q[j].x,q[j].y); 
81             swap(n,m);
82         }
83         for (int i=1;i<=Q;i++) printf("%lld\n",(ll)n*m-ans[i]);
84     } 
85    return 0;
86 }

 

题解:李超树

就是为了此神题才去学习了一下李超树。

以x坐标的移动来看可以到达的点的范围,从起点轴向两边形成不规则菱形。

分四块讨论,以左下角为例,线段树上的点为y坐标,维护递减折线。左区间的高度要大于等于右区间,所以更新的时候要把右区间的高度也维护进左区间。求折线下面积和的时候,维护一个右方高度下界,先统计右区间再统计左区间。

转载于:https://www.cnblogs.com/Scx117/p/9115327.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值