专题:数据结构之线段树
点击题号阅读题面
线段树真是博大精深...
---
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 }
----
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 }
----
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 }
----
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 }
----
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 }
----
G 难
普通的线段树无法保存一个区间内所有的数字,空间复杂度太高
和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&#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 }
----
题已经写得差不多了,慢慢更新题解吧