cyyz: Day 2 线段树知识整理

Day 2

上午的听课,哎~昏昏欲睡好吧。。

一、扫描线

知识点:

由于多边形千变万化,要想填充多边形内部的所有像素,需要找到一种合适的规则,能够沿着一个方向,一个像素不漏地把多边形内部填满,同时不污染多边形外部。于是我们发明了一条水平方向的扫描线,它从y=0开始,判断与多边形的交点,这些交点把扫描线分成了若干段,我们需要判断哪些段在多边形内部,哪些段在多边形外部,然后把内部的部分着色,完成后,令y=y+1,即扫描线上移一格,重复之前的操作,直到扫描线不再与多边形的任何部分相交。

例题(poj 1151):

 

代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 using namespace std;
 7 const int N=110;
 8 double w[N<<1];
 9 double x,y,dx,dy,ans;
10 int n,res=0,js;
11 
12 struct edge {
13     double l,r,h;
14     int f;
15 }e[N<<1];
16 
17 struct node {
18     int l,r,s;
19     double lc;
20 }q[N<<3];
21 
22 inline bool cmp(edge a,edge b) {
23     return a.h<b.h;
24 }
25 
26 inline void build (int i,int l,int r) {
27     q[i]=(node){l,r,0,0};
28     if(l==r) return;
29     int mid=(q[i].l+q[i].r)>>1;
30     build(i<<1,l,mid);
31     build(i<<1|1,mid+1,r);
32 }
33 
34 inline void push_up(int i) {
35     if(q[i].s) q[i].lc=w[q[i].r+1]-w[q[i].l]; 
36     else if(q[i].l==q[i].r) q[i].lc=0;
37     else q[i].lc=q[i<<1].lc+q[i<<1|1].lc;
38 }
39 
40 void up_date(int i,int l,int r,int v) {
41     if(q[i].l==l && q[i].r==r) {
42         q[i].s+=v;
43         push_up(i);
44         return;
45     }
46     int mid=(q[i].l+q[i].r)>>1;
47     if(r<=mid) up_date(i<<1,l,r,v);
48     else if(l>mid) up_date(i<<1|1,l,r,v);
49     else up_date(i<<1,l,mid,v),up_date(i<<1|1,mid+1,r,v);
50     push_up(i);
51 }
52 
53 inline void IU() {
54     e[js]=(edge) {x,dx,y,1};
55     w[js]=x;
56     e[js+1]=(edge){x,dx,dy,-1};
57     w[js+1]=dx;
58 }
59 
60 int main() {
61     while (scanf("%d",&n)==1 && n) {
62         js=0;
63         for(int i=0;i<n;++i) {
64             scanf("%lf%lf%lf%lf",&x,&y,&dx,&dy);
65             IU(); js+=2;
66         }
67         sort(e,e+js,cmp);
68         sort(w,w+js);
69         int k=1;
70         for(int i=1;i<js;++i)
71             if(w[i]!=w[i-1]) w[k++]=w[i];
72         build(1,0,k-1);
73         ans=0;
74         for(int i=0;i<js;++i) {
75             int l=lower_bound(w,w+k,e[i].l)-w;
76             int r=lower_bound(w,w+k,e[i].r)-w-1;
77             up_date(1,l,r,e[i].f);
78             ans+=(e[i+1].h-e[i].h)*q[1].lc;
79         } 
80         printf("Test case #%d\n",++res);
81         printf("Total explored area: %.2f\n\n",ans);
82     }
83     return 0;
84 }
85 //poj 1151
代码实现

 

二、线段树(大全)

知识点:

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。线段树至少支持下列操作:

1.Insert(t,x):将包含在区间 int 的元素 x 插入到树t中;

2.Delete(t,x):从线段树 t 中删除元素 x;

3.Search(t,x):返回一个指向树 t 中元素 x 的指针。

线段树代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int N=100000;
 5 int sum[N<<2],a[N+1];
 6 int n,m,k,L,R;
 7 
 8 inline int read() {
 9     int n=0,f=1;char ch=getchar();
10     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
11     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
12     return n*f;
13 }
14 
15 inline void push_up(int rt) {
16     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
17 }
18 
19 inline void build(int l,int r,int rt) {
20     if(l==r) {
21         sum[rt]=a[l];
22         return ;
23     }
24     int m=(l+r)>>1;
25     build(l,m,rt<<1),build(m+1,r,rt<<1|1);
26     push_up(rt);
27 }
28 
29 inline int query(int L,int R,int l,int r,int rt) {
30     if(L<=l&&r<=R) return sum[rt];
31     int s=0;
32     int m=(l+r)>>1;
33     if(L<=m) s+=query(L,R,l,m,rt<<1);
34     if(R>m) s+=query(L,R,m+1,r,rt<<1|1);
35     return s;
36 }
37 
38 inline void up_date(int L,int C,int l,int r,int rt) {
39     if(l==r) { 
40         sum[rt]+=C;
41         return;
42     }
43     int m=(l+r)>>1;
44     if(L<=m) up_date(L,C,l,m,rt<<1);
45     else up_date(L,C,m+1,r,rt<<1|1); 
46     push_up(rt);
47 }
48 
49 int main() {
50     n=read();
51     for(int i=1;i<=n;++i) a[i]=read();
52     build(1,n,1);
53     m=read();
54     for(int i=0;i<m;++i) {
55         k=read(),L=read(),R=read();
56         if(k==1) up_date(L,R,1,n,1);
57         if(k==2) printf("%d\n",query(L,R,1,n,1));
58     }
59     return 0;
60 }
代码实现

线段树(区间加及求和)代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #define N 1000001
 4 #define ll long long
 5 using namespace std;
 6 ll a[N],ans[N<<2],t[N<<2];
 7 ll bz,b,c,d,e,f,n,m;
 8 
 9 inline ll read() {
10     ll n=0,f=1;char ch=getchar();
11     while (ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
12     while (ch<='9'&&ch>='0') {n=n*10+ch-'0';ch=getchar();}
13     return n*f;
14 } 
15 
16 inline void pushup_(ll i) {
17     ans[i]=ans[i<<1]+ans[i<<1|1];
18 }
19 
20 inline void build(ll i,ll l,ll r) {
21     t[i]=0;
22     if(l==r) {
23         ans[i]=a[l];
24         return ;
25     }
26     ll mid=(l+r)>>1;
27     build(i<<1,l,mid);
28     build(i<<1|1,mid+1,r);
29     pushup_(i);
30 }
31 
32 inline void work_(ll i,ll l,ll r,ll k) {
33     t[i]=t[i]+k;
34     ans[i]=ans[i]+k*(r-l+1);
35 }
36 
37 inline void push_down(ll i,ll l,ll r) {
38     ll mid=(l+r)>>1;
39     work_(i<<1,l,mid,t[i]);
40     work_(i<<1|1,mid+1,r,t[i]);
41     t[i]=0;
42 }
43 
44 inline void _work(ll a,ll b,ll l,ll r,ll i,ll k) {
45     if(a<=l&&r<=b) {
46         ans[i]+=k*(r-l+1);
47         t[i]+=k;
48         return ;
49     }
50     push_down(i,l,r);
51     ll mid=(l+r)>>1;
52     if(a<=mid) _work(a,b,l,mid,i<<1,k);
53     if(b>mid) _work(a,b,mid+1,r,i<<1|1,k);
54     pushup_(i);
55 }
56 
57 inline ll query(ll a,ll b,ll l,ll r,ll i) {
58     ll s=0;
59     if(a<=l&&r<=b) return ans[i];
60     ll mid=(l+r)>>1;
61     push_down(i,l,r);
62     if(a<=mid) s+=query(a,b,l,mid,i<<1);
63     if(b>mid) s+=query(a,b,mid+1,r,i<<1|1);
64     return s;
65 }
66 
67 int main() {
68     n=read(),m=read();
69     for(ll i=1;i<=n;++i) a[i]=read();
70     build(1,1,n);
71     while(m--) {
72         bz=read();
73         if(bz==1) {
74             b=read(),c=read(),d=read();
75             _work(b,c,1,n,1,d);
76             continue;
77         }
78         if(bz==2) {
79             e=read(),f=read();
80             printf("%lld\n",query(e,f,1,n,1));
81             continue;
82         }
83     }
84     return 0;
85 }
代码实现

线段树(区间修改及询问)代码实现

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 typedef long long ll;
 5 const int N=1e6+10;
 6 ll t[N],bz[N],dz[N],L[N],R[N];
 7 int n,m,f,x,y;
 8 ll add;
 9 
10 inline int read() {
11     int n=0,f=1;char ch=getchar();
12     while (ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
13     while (ch<='9'&&ch>='0') {n=n*10+ch-'0';ch=getchar();}
14     return n*f;
15 } 
16 
17 inline ll readx() {
18     ll n=0,f=1;char ch=getchar();
19     while (ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
20     while (ch<='9'&&ch>='0') {n=n*10+ch-'0';ch=getchar();}
21     return n*f;
22 } 
23 
24 inline void _work(int i,int l,int r) {
25     L[i]=l,R[i]=r;
26     int mid=(l+r)>>1;
27     if(l==r) {
28         t[i]=dz[l];
29         return;
30     }
31     _work(i<<1,l,mid),_work(i<<1|1,mid+1,r);
32     t[i]=t[i<<1]+t[i<<1|1];
33 }
34 
35 inline void down_(int i) {
36     if(bz[i]) {
37         int mid=(L[i]+R[i])>>1;
38         t[i<<1]+=(mid-L[i]+1)*bz[i];
39         t[i<<1|1]+=(R[i]-mid)*bz[i];
40         bz[i<<1]+=bz[i];
41         bz[i<<1|1]+=bz[i];
42         bz[i]=0;
43     }
44 }
45 
46 inline void work_(int i,int l,int r,ll add) {
47     if(L[i]>=l && R[i]<=r) {
48         t[i]+=(R[i]-L[i]+1)*add;
49         bz[i]+=add;
50         return;
51     }
52     if(L[i]>r || R[i]<l)return;
53     down_(i);
54     work_(i<<1,l,r,add),work_(i<<1|1,l,r,add);
55     t[i]=t[i<<1]+t[i<<1|1];
56 }
57 
58 inline ll query(int i,int l,int r) {
59     if(L[i]>=l && R[i]<=r) return t[i];
60     if(L[i]>r || R[i]<l) return 0;
61     ll s=0;
62     down_(i);
63     s+=query(i<<1,l,r),s+=query(i<<1|1,l,r);
64     return s;
65 }
66 
67 int main() {
68     n=read();
69     for(int i=1;i<=n;++i) dz[i]=readx();
70     m=read();
71     _work(1,1,n);
72     for(int i=1;i<=m;++i) {
73         f=read();
74         switch(f) {
75             case 1:
76                 x=read(),y=read(),add=readx();
77                 work_(1,x,y,add);
78                 break;
79             case 2:
80                 x=read(),y=read();
81                 printf("%lld\n",query(1,x,y));
82                 break;
83             default:
84                 printf("Orz %%%");
85                 break;
86         }
87     }
88     return 0;
89 }
代码实现

线段树(区间加及求和)代码实现:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<string>
  5 #include<algorithm>
  6 #include<cmath>
  7 #define ll long long int
  8 using namespace std;
  9 int const N=4e5+10;
 10 
 11 struct Tre {
 12     ll sum, v, bz, l, r;
 13 }e[N];
 14 
 15 ll n,m,mod,L,R,val,bz;
 16 ll t[N];
 17 
 18 inline ll read() {
 19     ll n=0,f=1;char ch=getchar();
 20     while (ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
 21     while (ch<='9'&&ch>='0') {n=n*10+ch-'0';ch=getchar();}
 22     return n*f;
 23 } 
 24 
 25 inline void push_up(ll i) {
 26     e[i].sum=(e[i<<1].sum+e[i<<1|1].sum)%mod;
 27 }
 28 
 29 inline void build(ll l, ll r, ll i) {
 30     e[i].l=l,e[i].r=r,e[i].bz=1;
 31     if(l==r) {
 32         e[i].sum=t[l]%mod;
 33         return;
 34     }
 35     ll mid=(l+r)>>1;
 36     build(l,mid,i<<1),build(mid+1,r,i<<1|1);
 37     push_up(i);
 38 }
 39 
 40 inline void pushdown(ll i) {
 41     if(e[i].bz!=1) {
 42         e[i<<1].v*=e[i].bz;   e[i<<1|1].v*=e[i].bz;
 43         e[i<<1].bz*=e[i].bz;  e[i<<1|1].bz*=e[i].bz;
 44         e[i<<1].sum*=e[i].bz; e[i<<1|1].sum*=e[i].bz;
 45         e[i<<1].v%=mod; e[i<<1|1].v%=mod;
 46         e[i<<1].bz%=mod; e[i<<1|1].bz%=mod;
 47         e[i<<1].sum%=mod; e[i<<1|1].sum%=mod;
 48         e[i].bz=1;
 49     }
 50     if(e[i].v) {
 51         e[i<<1].v+=e[i].v; e[i<<1|1].v+=e[i].v;
 52         e[i<<1].sum+=(e[i<<1].r-e[i<<1].l+1)*e[i].v;
 53         e[i<<1|1].sum+=(e[i<<1|1].r-e[i<<1|1].l+1)*e[i].v;
 54         e[i<<1].v%=mod; e[i<<1|1].v%=mod;
 55         e[i<<1].sum%=mod; e[i<<1|1].sum%=mod;
 56         e[i].v=0;
 57     }
 58 }
 59 
 60 inline void work_(ll i) {
 61     if(e[i].l>=L && e[i].r<=R) {
 62         e[i].bz*=val%mod; e[i].bz%=mod;
 63         e[i].v*=val%mod; e[i].v%=mod;
 64         e[i].sum*=val%mod; e[i].sum%=mod;
 65         return;
 66     }
 67     pushdown(i);
 68     ll mid=(e[i].l+e[i].r)>>1;
 69     if(L<=mid) work_(i<<1);
 70     if(R>mid) work_(i<<1|1);
 71     push_up(i);
 72 }
 73 
 74 inline void _work(ll i) {
 75     if(e[i].l>=L && e[i].r<=R) {
 76         e[i].sum+=((e[i].r-e[i].l+1)*val)%mod;
 77         e[i].sum%=mod; e[i].v+=val%mod;
 78         e[i].v%=mod;
 79         return;
 80     }
 81     pushdown(i);
 82     ll mid=(e[i].l+e[i].r)>>1;
 83     if(L<=mid) _work(i<<1);
 84     if(R>mid) _work(i<<1|1);
 85     push_up(i);
 86 }
 87 
 88 inline ll query(ll i) {
 89     if(e[i].l>=L && e[i].r<=R) return e[i].sum%mod;
 90     pushdown(i);
 91     ll mid=(e[i].l+e[i].r)>>1, ret=0;
 92     if(L<=mid) ret=(ret+query(i<<1)%mod)%mod;
 93     if(R>mid) ret=(ret+query(i<<1|1)%mod)%mod;
 94     push_up(i);
 95     return ret%mod;
 96 }
 97 
 98 int main() {
 99     n=read(),m=read(),mod=read();
100     for(int i=1;i<=n;++i) t[i]=read();
101     build(1,n,1);
102     for(int i=1;i<=m;++i) {
103         bz=read();
104         if(bz==1) {
105             L=read(),R=read(),val=read();
106             work_(1);
107         } else if(bz==2) {
108             L=read(),R=read(),val=read();
109             _work(1);
110         } else {
111             L=read(),R=read();
112             printf("%d\n", query(1));
113         }
114     }
115     return 0;
116 }
代码实现

线段树(区间修改及询问,单点修改及询问) 代码实现:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<algorithm>
 6 #include<cmath>
 7 #define ll long long int
 8 using namespace std;
 9 int n,m,opt,b,c,x;
10 const int N=6e5+10;
11 
12 struct note {
13     int l,r,s;
14 } t[N]; 
15 
16 inline int read() {
17     int n=0,f=1;char ch=getchar();
18     while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
19     while (ch<='9' && ch>='0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
20     return n*f;
21 }
22 //建树 
23 inline void build(int k,int l,int r) {
24     int lc=k<<1,rc=k<<1|1;
25     t[k].l=l,t[k].r=r;
26     int mid=(l+r)/2;
27     if(l==r) {
28         t[k].s=read();
29         return;
30     }
31     build(lc,l,mid),build(rc,mid+1,r);
32     t[k].s=t[lc].s+t[rc].s;
33 }
34 //单点修改
35 inline void _change(int k,int p,int v) {
36     int lc=k<<1,rc=k<<1|1;
37     int l=t[k].l,r=t[k].r;
38     if(l==r) {
39         t[k].s+=v;
40         return ;
41     }
42     int mid=(l+r)>>1;
43     if(p<=mid) _change(lc,p,v);
44     else _change(rc,p,v);
45     t[k].s=t[lc].s+t[rc].s;
46 }
47 //区间修改
48 inline void change_(int k,int l,int r,int v) {
49     int lc=k<<1,rc=k<<1|1;
50     if(t[k].l==t[k].r) {
51         t[k].s+=v;
52         return ;
53     }
54     int mid=(t[k].l+t[k].r)>>1;
55     if(l<=mid) change_(lc,l,min(r,mid),v);
56     if(r>mid) change_(rc,max(l,mid+1),r,v);
57     t[k].s=t[lc].s+t[rc].s;
58 }
59 //单点查询
60 inline int _query(int k,int p) {    
61     int lc=k<<1,rc=k<<1|1;
62     int l=t[k].l,r=t[k].r;
63     if(l==r) return t[k].s;
64     int mid=(l+r)>>1;
65     if(p<=mid) return _query(lc,p);
66     else return _query(rc,p);
67 }
68 //区间查询
69 inline int query_(int k,int l,int r) {    
70     int lc=k<<1,rc=k<<1|1;
71     if(t[k].l==l&&t[k].r==r) return t[k].s;
72     int mid=(t[k].l+t[k].r)>>1,ans=0;
73     if(l<=mid) ans+=query_(lc,l,min(r,mid));
74     if(r>mid) ans+=query_(rc,max(l,mid+1),r);
75     return ans;
76 }
77 
78 int main() {
79     n=read();
80     build(1,1,n);
81     m=read();
82     for(int i=1;i<=m;++i) {
83         opt=read();
84         if(opt==1) {
85             b=read(),c=read(),x=read();
86             change_(1,b,c,x);
87         }
88         if(opt==2) {
89             b=read();
90             printf("%d\n",_query(1,b));
91         }
92         if(opt==3) {lue...}
93         if(opt==4) {lue...}
94     }
95     return 0;
96 }
代码实现
原文地址:https://www.cnblogs.com/Darkpurple/p/9419301.html