专题:数据结构之线段树

  模板题 A HDU 1754 I Hate It
  模板题 B POJ 3468 A Simple Problem with Integers
   dfs线段树优化(区间最值) C OpenJ_Bailian 2452 Sticks Problem
  模板题 D POJ 3264 Balanced Lineup
   递增数列的区间众数,离散化去重 E POJ 3368 Frequent values
   单点查询,区间最值 F HDU 2795 Billboard
   区间求GCD和区间求LCM,,唯一分解定理+位压缩,线段树优化 G HDU 3071 Gcd & Lcm game
  填数+求lis,离线化处理 H HDU 3564 Another LIS
   思维题目 区间最值,离散化/二分 I HDU 2305 WorstWeather Ever
   最长上升子序列变体 用线段树优化区间最值,离散化  //这个题目前无法提交评测 J ZOJ 3349 Special Subsequence
 

 贪心 线段树优化 区间最值

K ZOJ 2451 Minimizing maximizer
  反素数表 约瑟夫环的线段树优化 L POJ 2886 Who Gets the Most Candies?
  线段树上的插空位+特殊递推,离线化,二分查找 M HDU 4288 Coder
  和上题一样 N CodeForces 85D Sum of Medians
  转化为2维,排序后再降维 区间求和  O POJ 2481 Cows
  不会写.... P HDU 3950 Parking Log
   动态规划 线段树优化 Q HDU 4521 小明系列问题——小明序列
  模板题 需要标记 R HDU 1698 Just a Hook
  模板题 需要标记 S HDU 1166 敌兵布阵
  动态规划  线段树预处理信息  T
HDU 3016  
Man Down
  离线处理回答 区间求和 U HDU 3333 Turing Tree
  集合模拟 区间修改 区间求和 V POJ 3225 Help with Intervals
  ...并不需要线段树 W HDU 3297 Balancing the Scale
  ...并不需要线段树 X HDU 2991 Generate random numbers
  矩形交并,实际上,可以用stl中的堆来代替 Y CodeForces 35E Parade
  不会写.... Z UVA 12436 Rip Van Winkle's Code

点击题号阅读题面

线段树真是博大精深...

---

A

模板题:单点更新,求区间最值

 1 /**********************
 2 *@Name:
 3 *
 4 *@Author: Nervending
 5 *@Describtion:
 6 *@DateTime: 2018-02-11 08:43:44
 7 ***********************/
 8 #include <bits/stdc++.h>
 9 #define show(x) cout<<#x<<"="<<x<<endl
10 using namespace std;
11 const int maxn=1e5+10;
12 const int maxm=1e6+10;
13 const int INF=0x3f3f3f3f;
14 typedef long long ll;
15 typedef unsigned long long ull;
16 int casn,n,m,k;
17 
18 struct node{int l,r,num;}tr[maxm<<1];
19 int num[maxm];
20 void build(int now,int s,int t){
21     tr[now]=(node){s,t,num[s]};
22     if(s==t) return;
23     int mid=(s+t)>>1;
24     build(now<<1,s,mid);
25     build(now<<1|1,mid+1,t);
26     tr[now].num=max(tr[now<<1].num,tr[now<<1|1].num);
27 }
28 int query(int s,int t,int now){
29     int l=tr[now].l,r=tr[now].r;
30     if(s<=l&&r<=t) return tr[now].num;
31     int mid=(l+r)>>1,ans=0;
32     if(s<=mid) ans=query(s,t,now<<1);
33     if(t>mid) ans=max(ans,query(s,t,now<<1|1));
34     return ans;
35 }
36 void update(int pos,int x,int now){
37     int l=tr[now].l,r=tr[now].r;
38     if(l==r) {
39         tr[now].num=x;
40         return;
41     }
42     int mid=(l+r)>>1;
43     if(pos<=mid) update(pos,x,now<<1);
44     else update(pos,x,now<<1|1);
45     tr[now].num=max(tr[now<<1].num,tr[now<<1|1].num);
46 }
47 
48 inline int read(){
49     int ret=0,flag=1,ch=getchar();
50     while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
51     while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
52     return flag*ret;
53 }
54 
55 int main(){
56 //#define test
57 #ifdef test
58     freopen("in.txt","r",stdin);
59     freopen("out.txt","w",stdout);
60 #endif
61     while(~scanf("%d%d",&n,&m)){
62         for(int i=1;i<=n;i++){
63             num[i]=read();
64         }
65         build(1,1,n);
66         char ch;
67         while(m--){
68             ch='0';
69             while(ch!='Q'&&ch!='U') ch=getchar();
70             int a=read(),b=read();
71             if(ch=='Q') printf("%d\n",query(a,b,1));
72             else update(a,b,1);
73         }
74     }
75 
76 #ifdef test
77     fclose(stdin);
78     fclose(stdout);
79     system("out.txt");
80 #endif
81     return 0;
82 }
View Code

----

B

模板题:区间更新,求区间和

  1 /**********************
  2 *@Name:
  3 *
  4 *@Author: Nervending
  5 *@Describtion:
  6 *@DateTime: 2018-02-11 22:28:52
  7 ***********************/
  8 #include <cstdio>
  9 #include <string.h>
 10 #include <iostream>
 11 #define show(x) cout<<#x<<"="<<x<<endl
 12 using namespace std;
 13 const int maxn=1e5+10;
 14 const int maxm=5e5+10;
 15 const int INF=0x3f3f3f3f;
 16 typedef long long ll;
 17 typedef unsigned long long ul;
 18 int casn,n,m,k;
 19 struct node{int l,r;long long data,tag;int len(){return r-l+1;}int mid(){return (l+r)>>1;}};
 20 node lst[maxm];
 21 int num[maxm];
 22 inline void clear(int now){
 23     long long &tag=lst[now].tag;
 24     if(tag){
 25         lst[now<<1].tag+=tag;
 26         lst[now<<1|1].tag+=tag;
 27         lst[now<<1].data+=tag*lst[now<<1].len();
 28         lst[now<<1|1].data+=tag*lst[now<<1|1].len();
 29         tag=0;
 30     }
 31 }
 32 void make(int s,int t,int now){
 33     lst[now]=(node){s,t,num[s],0};
 34     if(s==t) return;
 35     int mid=(s+t)>>1;
 36     make(s,mid,now<<1);
 37     make(mid+1,t,now<<1|1);
 38     lst[now].data=lst[now<<1].data+lst[now<<1|1].data;
 39 }
 40 void add(int s,int t,long long x,int now){
 41     node &nd=lst[now];
 42     if(s<=lst[now].l&&t>=lst[now].r){
 43         lst[now].tag+=x;
 44         lst[now].data+=x*lst[now].len();
 45         return;
 46     }
 47     clear(now);
 48     int mid=lst[now].mid();
 49     if(s<=mid) add(s,t,x,now<<1);
 50     if(t>mid)  add(s,t,x,now<<1|1);
 51     lst[now].data=lst[now<<1].data+lst[now<<1|1].data;
 52 }
 53 long long query(int s,int t,int now){
 54     node& nd=lst[now];
 55     if(s<=lst[now].l&&t>=lst[now].r){
 56         return lst[now].data;
 57     }
 58     clear(now);
 59     int mid=lst[now].mid();
 60     long long sum=0;
 61     if(s<=mid) sum+=query(s,t,now<<1);
 62     if(t>mid) sum+=query(s,t,now<<1|1);
 63     return sum;
 64 }
 65 inline int read(){
 66     int num=0,flag=1,ch=getchar();
 67     while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
 68     while(ch>='0'&&ch<='9'){num=num*10+ch-'0',ch=getchar();}
 69     return flag*num;
 70 }
 71 
 72 int main(){
 73 //#define test
 74 #ifdef test
 75     freopen("in.txt","r",stdin);
 76     freopen("out.txt","w",stdout);
 77 #endif
 78 
 79     while(~scanf("%d%d",&n,&m)){
 80     for(int i=1;i<=n;i++){
 81             num[i]=read();
 82         }
 83         make(1,n,1);
 84         int a,b,c,ch;
 85         while(m--){
 86             ch=0;
 87             while(ch!='Q'&&ch!='C')ch=getchar();
 88             a=read(),b=read();
 89             if(ch=='Q') {
 90                 printf("%lld\n",query(a,b,1));
 91             }
 92             else {
 93                 c=read();
 94                 add(a,b,c,1);
 95             }
 96         }
 97     }
 98 
 99 #ifdef test
100     fclose(stdin);
101   fclose(stdout);
102     system("out.txt");
103 #endif
104     return 0;
105 }
View Code

 ----

C

dfs,每次分为三段

 1 /**********************
 2 *@Name:
 3 *
 4 *@Author: Nervending
 5 *@Describtion:
 6 *@DateTime: 2018-02-17 17:32:19
 7 ***********************/
 8 #include <bits/stdc++.h>
 9 #define show(x) cout<<#x<<"="<<x<<endl
10 using namespace std;
11 const int maxn=1e5+10;
12 const int maxm=1e6+10;
13 const int INF=0x3f3f3f3f;
14 typedef long long ll;
15 typedef unsigned long long ull;
16 int casn,n,m,k,s[maxn],num[maxn];
17 struct node {int l,r,max;int mid(){return (l+r)>>1;}};
18 node lst[maxm];
19 void make(int s,int t,int now){
20     lst[now]=(node){s,t,0};
21     if(s==t) return;
22     int mid=(s+t)>>1;
23     make(s,mid,now<<1);
24     make(mid+1,t,now<<1|1);
25 }
26 void update(int pos,int x,int now){
27     node &nd=lst[now];
28     if(pos<nd.l||pos>nd.r) return;
29     if(nd.l==nd.r){nd.max=x;return;}
30     update(pos,x,now<<1);update(pos,x,now<<1|1);
31     nd.max=max(lst[now<<1].max,lst[now<<1|1].max);
32 }
33 int query(int s,int t,int now){
34     node& nd=lst[now];
35     if(t<nd.l||s>nd.r) return 0;
36     if(s<=nd.l&&t>=nd.r) return nd.max;
37     return max(query(s,t,now<<1),query(s,t,now<<1|1));
38 }
39 inline int read(){
40     int num=0,flag=1,ch=getchar();
41     while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
42     while(ch>='0'&&ch<='9'){num=(num<<3+num<<1)+ch-'0',ch=getchar();}
43     return flag*num;
44 }
45 
46 int main(){
47 //#define test
48 #ifdef test
49     freopen("in.txt","r",stdin);
50     freopen("out.txt","w",stdout);
51 #endif
52 
53     while(~scanf("%d%d",&n,&m)){
54         for(int i=0;i<n;i++){
55             num[i]=s[i]=read();
56         }
57         sort(num,num+n);
58         k=unique(num,num+n)-num;
59         make(1,k,1);
60         int ans=0;
61         for(int i=0;i<n;i++){
62             int l=lower_bound(num,num+k,s[i]-m)-num;
63             int r=upper_bound(num,num+k,s[i]+m)-num-1;
64             int len=query(l,r,1);
65             ans=max(ans,len+1);
66             update(lower_bound(num,num+k,s[i])-num,len+1,1);
67         }
68         printf("%d\n",ans);
69     }
70 
71 #ifdef test
72     fclose(stdin);
73   fclose(stdout);
74     system("out.txt");
75 #endif
76     return 0;
77 }
View Code

----

D 略

----

E

由于是递增的,只需要线性的去重就行了

去重之后,建立线段树,就行

 1 /**********************
 2   *@Name:
 3 *
 4 *@Author: Nervending
 5 *@Describtion:
 6 *@DateTime: 2018-02-13 12:57:50
 7 ***********************/
 8 #include <cstdio>
 9 #include <algorithm>
10 #define show(x) cout<<#x<<"="<<x<<endl
11 using namespace std;
12 const int maxn=1e5+10;
13 const int maxm=5e5+10;
14 const int INF=0x3f3f3f3f;
15 typedef long long ll;
16 typedef unsigned long long ull;
17 int casn,n,m,k,cnt;
18 int s[maxn],pos[maxn],sum[maxn],num[maxn];
19 struct node{
20     int l,r,mx;
21     int mid(){return (l+r)>>1;}
22 }lst[maxm];
23 void make(int s,int t,int now){
24     lst[now]=(node){s,t,num[s]};
25     if(s==t) return;
26     int mid=(s+t)>>1;
27     make(s,mid,now<<1);
28     make(mid+1,t,now<<1|1);
29     lst[now].mx=max(lst[now<<1].mx,lst[now<<1|1].mx);
30 }
31 int query(int s,int t,int now){
32     node &nd=lst[now];
33     if(s<=nd.l&&t>=nd.r){
34         return nd.mx;
35     }
36     int mid=nd.mid();
37     int ans=0;
38     if(s<=mid) ans=query(s,t,now<<1);
39     if(t>mid)  ans=max(ans,query(s,t,now<<1|1));
40     return ans;
41 }
42 inline int read(){
43     int num=0,flag=1,ch=getchar();
44     while(ch<'0'||ch>'9'){if(ch=='-')flag=-1;ch=getchar();}
45     while(ch>='0'&&ch<='9'){num=num*10+ch-'0',ch=getchar();}
46     return num*flag;
47 }
48 
49 int main(){
50 //#define test
51 #ifdef test
52     freopen("in.txt","r",stdin);
53     freopen("out.txt","w",stdout);
54 #endif
55     while(~scanf("%d",&n)){
56         if(n==0) break;
57         m=read();
58         for(int i=1;i<=n;i++){
59             s[i]=read();
60             num[i]=1;
61             pos[i]=i;
62         }
63         cnt=1;
64         for(int i=2;i<=n;i++){
65             if(s[i]==s[i-1]){
66                 num[cnt]++;
67                 pos[i]=cnt;
68             }else{
69                 pos[i]=++cnt;
70             }
71         }
72         for(int i=1;i<=cnt;i++){
73             sum[i]=sum[i-1]+num[i];
74         }
75         make(1,cnt,1);
76         while(m--){
77             int a=read(),b=read();
78             int l=pos[a],r=pos[b];
79             int ans=0;
80             if(l==r) ans=(b-a+1);
81             else {
82                 ans=max(sum[l]-a+1,b-sum[r-1]);
83                 if(r-l>1){
84                     ans=max(ans,query(l+1,r-1,1));
85                 }
86             }
87             printf("%d\n",ans);
88         }
89     }
90 
91 
92 #ifdef test
93     fclose(stdin);
94   fclose(stdout);
95     system("out.txt");
96 #endif
97     return 0;
98 }
View Code

----

F

可以稍微变形

 1 /**********************
 2 *@Name:
 3 *
 4 *@Author: Nervending
 5 *@Describtion:
 6 *@DateTime: 2018-02-13 21:38:09
 7 ***********************/
 8 #include <bits/stdc++.h>
 9 #define show(x) cout<<#x<<"="<<x<<endl
10 using namespace std;
11 const int maxn=2e5+10;
12 const int maxm=1e6+10;
13 const int INF=0x3f3f3f3f;
14 typedef long long ll;
15 typedef unsigned long long ull;
16 int casn,n,m,k;
17 struct node{
18     int l,r,mx;
19     int mid(){return (l+r)>>1;}
20 }lst[maxm];
21 void make(int s,int t,int now){
22     lst[now]=(node){s,t,m};
23     if(s==t) return;
24     int mid=(s+t)>>1;
25     make(s,mid,now<<1);
26     make(mid+1,t,now<<1|1);
27 }
28 int update(int x,int now){
29     node& nd=lst[now];
30     if(nd.l==nd.r){
31         nd.mx-=x;
32         return nd.l;
33     }
34     int mid=nd.mid(),ret;
35     if(lst[now<<1].mx>=x) ret=update(x,now<<1);
36     else ret=update(x,now<<1|1);
37     nd.mx=max(lst[now<<1].mx,lst[now<<1|1].mx);
38     return ret;
39 }
40 inline int read(){
41     int num=0,flag=1,ch=getchar();
42     while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
43     while(ch>='0'&&ch<='9'){num=num*10+ch-'0',ch=getchar();}
44     return flag*num;
45 }
46 
47 int main(){
48 //#define test
49 #ifdef test
50     freopen("in.txt","r",stdin);
51     freopen("out.txt","w",stdout);
52 #endif
53     while(~scanf("%d%d%d",&n,&m,&k)){
54         n=min(n,k);
55         make(1,n,1);
56         while(k--){
57             int len=read();
58             if(len>lst[1].mx)puts("-1");
59             else printf("%d\n",update(len,1));
60         }
61     }
62 
63 
64 #ifdef test
65     fclose(stdin);
66   fclose(stdout);
67     system("out.txt");
68 #endif
69     return 0;
70 }
View Code

----

普通的线段树无法保存一个区间内所有的数字,空间复杂度太高

和GCD,LCM有关的我们就考虑唯一分解定律,gcd就是所有素因子取交集,lcm就是所有素因子取并集

所以实际上我们不需要去保存所有数字的信息,只需要保存所有素因数的个数的交集和并集就行了

但是1-100的素数有25个,需要每个节点一个长度25的数组,而且比较的常数也不低,很可能爆空间

但是同时也发现了只有25个素数,考虑位压缩

我们用0和1表示是否有这个因子,对于可以重复出现的因子,比如:

  2*2*2*2*2*2=64,3*3*3*3=81,5*5=25,7*7=49

我们就多分配几位....但如果是int的话并不能直接堆砌

就拿2,3,5,7来看,分别需要6个,4个,2个,2个,一共12个,还有其他的21个素数呢,int就不够了

所以用longlong就行...

但网上有空间复杂度更好的解法,就是直接用2进制表示个数

那么2最多到6,也就是3位,3是四个也是3位,5和7依然是2位,这就一共是10位

算上其余的21个素数,刚好31位,不会吧爆ing

简单来说,最终的位含义是:

2,2,2,2,3,3,3,3,5,5,7,7,11,13...89,97.一共31位

用2个函数,一个压缩,一个还原.

需要4个辅助常数表,分别是

  素数表prime,用于判定因子

  素数位置表bpos,位操作时快速定位到每个素数所对应的位

  素数幂表,pw 用于还原2,3,5,7的幂

  位操作数 b2-b97,用于位操作的交集和并集

2个区间查询,rmax和rmin rmax取并集,rmin取交集

1个区间修改 update 和更新最值一样,只不过变成了交集和并集

上个最优的代码吧

  1 /**********************
  2 *@Name:
  3 *
  4 *@Author: Nervending
  5 *@Describtion:
  6 *@DateTime: 2018-02-14 01:00:58
  7 ***********************/
  8 #include <bits/stdc++.h>
  9 #define show(x) cout<<#x<<"="<<x<<endl
 10 using namespace std;
 11 const int maxn=1e5+10;
 12 const int maxm=1e6+10;
 13 const int INF=0x3f3f3f3f;
 14 typedef long long ll;
 15 typedef unsigned long long ull;
 16 const int prime[25]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
 17 const int bpos[25]={28,25,23,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
 18 const int pw[4][10]={{1,2,4,8,16,32,64},{1,3,9,27,81},{1,5,25},{1,7,49}};
 19 const int b2=0x70000000,b3=0x0e000000,b5=0x01800000;
 20 const int b7=0x00600000,b97=0x001fffff;
 21 int casn,n,m,k;
 22 int num[maxn];
 23 int tes[maxn];
 24 inline int read(){
 25     int num=0,flag=1,ch=getchar();
 26     while(ch<'0'||ch>'9'){if(ch=='-')flag=-1;ch=getchar();}
 27     while(ch>='0'&&ch<='9'){num=(num<<1)+(num<<3)+ch-'0';ch=getchar();}
 28     return num*flag;
 29 }
 30 struct node{
 31     int l,r,mx,mn;
 32     int mid(){return (l+r)>>1;}
 33 }lst[maxm];
 34 
 35 inline int in(int x,int y){
 36     return min(x&b2,y&b2)|min(x&b3,y&b3)|min(x&b5,y&b5)|min(x&b7,y&b7)|((x&b97)&(y&b97));
 37 }
 38 inline int un(int x,int y){
 39     return max(x&b2,y&b2)|max(x&b3,y&b3)|max(x&b5,y&b5)|max(x&b7,y&b7)|((x&b97)|(y&b97));
 40 }
 41 inline int tobit(int num){
 42     int cnt,bit=0;
 43     for(int i=0;i<25&&num;i++){
 44         for(cnt=0;num%prime[i]==0;num/=prime[i]) cnt++;
 45         bit|=cnt<<bpos[i];
 46     }
 47     return bit;
 48 }
 49 inline int todig(int bit,int mod){
 50     int cnt,num=1;
 51     for(int i=0,k=0;i<4;i++){
 52         k=bit>>bpos[i];
 53         num=num*pw[i][k]%mod;
 54         bit^=k<<bpos[i];
 55     }
 56     for(int i=4;i<25;i++){
 57         if(bit&(1<<bpos[i])) num=num*prime[i]%mod;
 58     }
 59     return num;
 60 }
 61 void make(int s,int t,int now){
 62     lst[now]=(node){s,t,num[s],num[s]};
 63     if(s==t) return;
 64     int mid=lst[now].mid();
 65     make(s,mid,now<<1);
 66     make(mid+1,t,now<<1|1);
 67     lst[now].mx=un(lst[now<<1].mx,lst[now<<1|1].mx);
 68     lst[now].mn=in(lst[now<<1].mn,lst[now<<1|1].mn);
 69 }
 70 void update(int pos,int x,int now){
 71     node &nd=lst[now];
 72     if(nd.l==nd.r){
 73         nd.mx=nd.mn=x;
 74         return;
 75     }
 76     int mid=nd.mid();
 77     if(pos<=mid)update(pos,x,now<<1);
 78     else update(pos,x,now<<1|1);
 79     nd.mx=un(lst[now<<1].mx,lst[now<<1|1].mx);
 80     nd.mn=in(lst[now<<1].mn,lst[now<<1|1].mn);
 81     int t=nd.mn;
 82 }
 83 int rmax(int s,int t,int now){
 84     node &nd=lst[now];
 85     if(s<=nd.l&&t>=nd.r){
 86         return nd.mx;
 87     }
 88     int ret=0,mid=nd.mid();
 89     if(s<=mid) ret=rmax(s,t,now<<1);
 90     if(t>mid)  ret=un(ret,rmax(s,t,now<<1|1));
 91     return ret;
 92 }
 93 int rmin(int s,int t,int now){
 94     node &nd=lst[now];
 95     if(s<=nd.l&&t>=nd.r){
 96         return nd.mn;
 97     }
 98     int ret=0x7fffffff,mid=nd.mid();
 99     if(s<=mid) ret=rmin(s,t,now<<1);
100     if(t>mid)  ret=in(ret,rmin(s,t,now<<1|1));
101     return ret;
102 }
103 
104 int main(){
105 //#define test
106 #ifdef test
107     freopen("in.txt","r",stdin);
108     freopen("out.txt","w",stdout);
109 #endif
110 
111     while(~scanf("%d%d",&n,&m)){
112         for(int i=1;i<=n;i++){
113             k=read();
114             num[i]=tobit(k);
115         }
116         make(1,n,1);
117         while(m--){
118             int a,b,c=getchar();
119             while(c!='C'&&c!='L'&&c!='G'){
120                 c=getchar();
121             }
122             if(c=='C'){
123                 a=read(),b=read();
124                 update(a,tobit(b),1);
125             }else {
126                 a=read(),b=read();
127                 int ans=0;
128                 if(c=='L') ans=rmax(a,b,1);
129                 else ans=rmin(a,b,1);
130                 c=read();
131                 printf("%u\n",todig(ans,c));
132             }
133         }
134     }
135 
136 #ifdef test
137     fclose(stdin);
138   fclose(stdout);
139     system("out.txt");
140 #endif
141     return 0;
142 }
View Code

----

题已经写得差不多了,慢慢更新题解吧

posted @ 2018-02-11 07:19  nervending  阅读(219)  评论(0编辑  收藏  举报