bzoj3165 segment 超哥线段树

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3165

题意:动态增加线段,求出横坐标纵坐标最高的被覆盖点所在线段。

这个题要用到李超线段树(orz李超)……大概这是李超那篇论文出现后第二年的题?不管了直接介绍这一数据结构。李超线段树的目的就是查询出每个点被线段覆盖的情况,操作无非就是插入线段和查询两件事。

插入线段:首先计算出原有线段和现在线段在这个区间之内的函数值,如果新线段一直大直接修改返回,如果一直小也直接返回,否则递归修改至单点或全部返回为止。

查询线段:不断地递归查询,从根节点整条数轴一直查询到单点,期间找到最值就进行修改。

可以证明,单次修改时间复杂度$O(log^2n)$,单次查询时间复杂度$O(logn)$,因此复杂度完全足够。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<map>
 6 using namespace std;
 7 const int maxn=100005,maxp=40005;const double eps=1e-9;
 8 struct node
 9 {
10     double k,b;int id;bool vis;
11 }S[maxn<<2];
12 int dcmp(double x)
13 {
14     return (x>eps)-(x<-eps);
15 }
16 #define mid ((l+r)>>1)
17 #define lc root<<1
18 #define rc root<<1|1
19 #define lson lc,l,mid
20 #define rson rc,mid+1,r
21 inline void solve(int root,int l,int r,int idx,double k,double b)
22 {
23     if(!S[root].vis)
24     {
25         S[root].k=k,S[root].b=b,S[root].id=idx,S[root].vis=1;
26         return;
27     }
28     double y0=S[root].k*l+S[root].b,y1=k*l+b,y2=S[root].k*r+S[root].b,y3=k*r+b;
29     if(dcmp(y1-y0)>0&&dcmp(y3-y2)>0)
30     {
31         if(dcmp(k-S[root].k)==0&&dcmp(b-S[root].b)==0)return;
32         S[root].k=k,S[root].b=b,S[root].id=idx;
33         return;
34     }
35     if(dcmp(y1-y0)<=0&&dcmp(y3-y2)<=0)return;
36     solve(lson,idx,k,b);solve(rson,idx,k,b);
37 }
38 inline void insert(int root,int l,int r,int L,int R,int idx,double k,double b)
39 {
40     if(L<=l&&r<=R){solve(root,l,r,idx,k,b);return;}
41     if(L<=mid)insert(lson,L,R,idx,k,b);if(R>mid)insert(rson,L,R,idx,k,b);
42 }
43 inline void insert(int x0,int x1,int y0,int y1,int num)
44 {
45     int L=x0,R=x1;double k=1.0*(y1-y0)/(1.0*(x1-x0)),b=y0-x0*k;int idx=num;insert(1,1,maxp,L,R,idx,k,b);
46 }
47 double ans;int ans_id;
48 inline void query(int root,int l,int r,int pos)
49 {
50     double x=S[root].k*pos+S[root].b;
51     if(dcmp(x-ans)>0||dcmp(x-ans)==0&&S[root].id<ans_id)ans=x,ans_id=S[root].id;
52     if(l==r)return;
53     if(pos<=mid)query(lson,pos);else query(rson,pos);
54 }
55 int a[maxn],id[maxn];
56 int haha()
57 {
58     int n;scanf("%d",&n);int lastans=0;
59     int opt,x0,y0,x1,y1,x,num=0;
60     while(n--)
61     {
62         scanf("%d",&opt);
63         if(!opt)
64         {
65             scanf("%d",&x),x=((x+lastans-1)%39989+1);
66             ans=ans_id=0;query(1,1,maxp,x);
67             if(ans<a[x]||ans==a[x]&&id[x]<ans_id)ans_id=id[x];
68             printf("%d\n",lastans=ans_id);
69         }
70         else
71         {
72             num++;scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
73             x0=(x0+lastans-1)%39989+1,y0=(y0+lastans-1)%(int)1e9+1,x1=(x1+lastans-1)%39989+1,y1=(y1+lastans-1)%(int)1e9+1;
74             if(x0>x1)swap(x0,x1),swap(y0,y1);
75             if(x0==x1)
76             {
77                 if(max(y0,y1)>a[x0])a[x0]=max(y0,y1),id[x0]=num;
78             }
79             else insert(x0,x1,y0,y1,num);
80         }
81     }
82 }
83 int sb=haha();
84 int main(){;}
bzoj3165

 

转载于:https://www.cnblogs.com/Loser-of-Life/p/7590334.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值