题集来源:链接
发现了一个大牛的博客,线段树讲的很精彩。链接在此。
一般用线划掉的都是没有什么意义的水题。。。或者很久之前做过的,把代码粘过来了。
敌兵布阵
题意:单点更新,区间求和。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 6 const int maxn=50010; 7 int sum[maxn<<2]; 8 9 void pushup(int rt){ 10 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 11 } 12 void build(int l,int r,int rt){ 13 if(l==r){ 14 scanf("%d",&sum[rt]); 15 return ; 16 } 17 int m=(l+r)>>1; 18 build(lson); 19 build(rson); 20 pushup(rt); 21 } 22 void update(int p,int x,int l,int r,int rt){ 23 if(l==r){ 24 sum[rt]+=x; 25 return; 26 } 27 int m=(l+r)>>1; 28 if(p<=m) update(p,x,lson); 29 else update(p,x,rson); 30 pushup(rt); 31 } 32 int query(int L,int R,int l,int r,int rt){ 33 if(L<=l&&r<=R){ 34 return sum[rt]; 35 } 36 int m=(l+r)>>1; 37 int ans=0; 38 if(L<=m) ans+=query(L,R,lson); 39 if(m<R) ans+=query(L,R,rson); 40 return ans; 41 } 42 43 int n; 44 char s[6]; 45 int x,y; 46 int main(){ 47 int t; 48 int kase=0; 49 scanf("%d",&t); 50 while(t--){ 51 scanf("%d",&n); 52 build(1,n,1); 53 printf("Case %d: ",++kase); 54 while(1){ 55 scanf("%s",s); 56 if(strcmp(s,"End")==0) break; 57 scanf("%d%d",&x,&y); 58 if(s[0]=='Q'){ 59 printf("%d ",query(x,y,1,n,1)); 60 continue; 61 } 62 if(s[0]=='S') y=-y; 63 update(x,y,1,n,1); 64 } 65 } 66 return 0; 67 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=50010; 5 int sum[maxn<<2],N; 6 int n; 7 void build(){ 8 N=1;while(N<n+2) N<<=1; 9 for(int i=1;i<=n;i++) scanf("%d",&sum[N+i]); 10 for(int i=N-1;i;i--){ 11 sum[i]=sum[i<<1]+sum[i<<1|1]; 12 } 13 } 14 int query(int L,int R){ 15 int ans=0; 16 for(int s=N+L-1,t=N+R+1;s^t^1;s>>=1,t>>=1){ 17 if(~s&1) ans+=sum[s^1]; 18 if( t&1) ans+=sum[t^1]; 19 } 20 return ans; 21 } 22 void update(int p,int x){ 23 for(int s=N+p;s;s>>=1) sum[s]+=x; 24 } 25 int main(){ 26 int t; 27 int kase=0; 28 scanf("%d",&t); 29 while(t--){ 30 scanf("%d",&n); 31 build(); 32 printf("Case %d: ",++kase); 33 char s[10]; 34 int x,y; 35 while(scanf("%s",s)){ 36 if(s[0]=='E') break; 37 scanf("%d%d",&x,&y); 38 if(s[0]=='Q'){ 39 printf("%d ",query(x,y)); 40 continue; 41 } 42 if(s[0]=='S') y=-y; 43 update(x,y); 44 } 45 } 46 return 0; 47 }
I Hate It
题意:单点更新,求区间最大值。
1 #include<cstdio> 2 #include<iostream> 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 using namespace std; 6 const int maxn=200010; 7 int f[maxn<<2]; 8 inline pushup(int rt) 9 { 10 f[rt]=max(f[rt<<1],f[rt<<1|1]); 11 } 12 13 void build(int l,int r,int rt) 14 { 15 if(l==r) 16 { 17 scanf("%d",&f[rt]); 18 return ; 19 } 20 int m=(l+r)>>1; 21 build(lson); 22 build(rson); 23 pushup(rt); 24 } 25 26 void update(int p,int sc,int l,int r,int rt) 27 { 28 if(l==r) { 29 f[rt]=sc; 30 return; 31 } 32 int m=(l+r)>>1; 33 if(p<=m) update(p,sc,lson); 34 else update(p,sc,rson); 35 pushup(rt); 36 } 37 38 int query(int L,int R,int l,int r,int rt) 39 { 40 if(L<=l&&r<=R) return f[rt]; 41 int m=(l+r)>>1; 42 int ans=-1; 43 if(L<=m) ans=max(ans,query(L,R,lson)); 44 if(R>m) ans=max(ans,query(L,R,rson)); 45 return ans; 46 } 47 48 int main() 49 { 50 int n,m,a,b; 51 while(scanf("%d%d",&n,&m)!=EOF) 52 { 53 build(1,n,1); 54 char s[2]; 55 while(m--) 56 { 57 scanf("%s%d%d",s,&a,&b); 58 if(s[0]=='Q') printf("%d ",query(a,b,1,n,1)); 59 else update(a,b,1,n,1); 60 } 61 62 } 63 return 0; 64 }
Minimum Inversion Number
题意:找最小逆序数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 6 const int maxn=5010; 7 int sum[maxn<<2]; 8 9 void pushup(int rt){ 10 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 11 } 12 void build(int l,int r,int rt){ 13 if(l==r){ 14 sum[rt]=1; 15 return ; 16 } 17 int m=(l+r)>>1; 18 build(lson); 19 build(rson); 20 pushup(rt); 21 } 22 23 void update(int p,int l,int r,int rt){ 24 if(l==r){ 25 sum[rt]=0; 26 return; 27 } 28 int m=(l+r)>>1; 29 if(p<=m) update(p,lson); 30 else update(p,rson); 31 pushup(rt); 32 } 33 int query(int L,int R,int l,int r,int rt){ 34 if(L<=l&&r<=R) { 35 return sum[rt]; 36 } 37 int m=(l+r)>>1; 38 int ans=0; 39 if(L<=m) ans+=query(L,R,lson); 40 if(R>m) ans+=query(L,R,rson); 41 return ans; 42 } 43 int a[maxn]; 44 int n; 45 46 int main(){ 47 while(scanf("%d",&n)!=EOF){ 48 build(1,n,1); 49 int ans=0; 50 for(int i=1;i<=n;i++){ 51 scanf("%d",&a[i]); 52 a[i]++; 53 update(a[i],1,n,1); 54 ans+=query(1,a[i],1,n,1); 55 } 56 //printf("逆序数==%d ",ans); 57 int temp=ans; 58 for(int i=1;i<n;i++){ 59 temp=temp-(a[i]-1)+(n-a[i]); 60 ans=min(ans,temp); 61 } 62 printf("%d ",ans); 63 } 64 }
Billboard
题意:在板子上贴海报,尽量从左下方开始贴,问最低贴在哪层。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 const int maxn=200010; 6 int maxx[maxn<<2]; 7 int h,w,m; 8 void pushup(int rt){ 9 maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]); 10 } 11 12 void build(int l,int r,int rt){ 13 if(l==r){ 14 maxx[rt]=w; 15 return ; 16 } 17 int m=(l+r)>>1; 18 build(lson); 19 build(rson); 20 pushup(rt); 21 } 22 23 int query(int x,int l,int r,int rt){ 24 if(l==r){ 25 maxx[rt]-=x; 26 return l; 27 } 28 int m=(l+r)>>1; 29 int ans; 30 if(maxx[rt<<1]>=x) ans=query(x,lson); 31 else ans=query(x,rson); 32 pushup(rt); 33 34 return ans; 35 } 36 37 int main(){ 38 while(scanf("%d%d%d",&h,&w,&m)!=EOF){ 39 int n=min(h,m); 40 build(1,n,1); 41 while(m--){ 42 int x; 43 scanf("%d",&x); 44 int ans; 45 if(maxx[1]<x) ans=-1; 46 else ans=query(x,1,n,1); 47 printf("%d ",ans); 48 } 49 } 50 return 0; 51 }
Buy Tickets
题意:n个人排队,告诉你每个人插队的位置,输出最后的队列。
一开始用链表写的,看别人都说超时我是WA,,后来发现链表也写挂了=_=||
思路比较巧妙,逆序进行排队,找到第p个空位插进去就行。
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 const int maxn=200010; 7 int sum[maxn<<2]; 8 int a[maxn]; 9 10 void pushup(int rt){ 11 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 12 } 13 void build(int l,int r,int rt){ 14 if(l==r){ 15 sum[rt]=1; 16 return ; 17 } 18 int m=(l+r)>>1; 19 build(lson); 20 build(rson); 21 pushup(rt); 22 } 23 24 void query(int p,int x,int l,int r,int rt){ 25 if(l==r){ 26 sum[rt]=0; 27 a[l]=x; 28 return ; 29 } 30 int m=(l+r)>>1; 31 if(p<=sum[rt<<1]) query(p,x,lson); 32 else query(p-sum[rt<<1],x,rson); 33 pushup(rt); 34 } 35 int n,p[maxn],x[maxn]; 36 int main(){ 37 while(scanf("%d",&n)!=EOF){ 38 build(1,n,1); 39 for(int i=0;i<n;i++){ 40 scanf("%d%d",&p[i],&x[i]); 41 } 42 for(int i=n-1;i>=0;i--){ 43 query(p[i]+1,x[i],1,n,1); 44 } 45 for(int i=1;i<=n;i++) 46 printf("%d%c",a[i],i==n?' ':' '); 47 } 48 }
Coder
题意:向空集中加入或者删除一些数,求剩下的数,从小到大排序后,id除以5余3的数的和。
纠结了很久的一道题,看网上的题解说的也不是很明白,我当时脑子又有点混乱,一直不会。。。
首先,最多一万个数,以这一万个下标建立一棵线段树,每个节点里存id余数分别为0到4的和,还要记录儿子的数量。
父亲的mod[i]和左二子的mod[i]是一个意义,至于右儿子,要考虑左二子的sz,因为它的余数都要加上左二子的sz。
还有因为进行离散化离线处理,下标从0开始,所以原题让求的余3等价于余2.
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 #define lson l,m,rt<<1 7 #define rson m+1,r,rt<<1|1 8 #define ll long long 9 #define CLR(m,a) memset(m,a,sizeof(m)) 10 const int maxn=100010; 11 12 struct Seg{ 13 int sz; 14 ll mod[5]; 15 }; 16 Seg seg[maxn*3]; 17 int a[maxn],b[maxn],vis[maxn]; 18 int n; 19 char s[10]; 20 21 void update(int p,int v,int l,int r,int rt){ 22 if(l==r){ 23 seg[rt].sz=v; 24 seg[rt].mod[0]=a[p]*v; 25 return ; 26 } 27 int m=(l+r)>>1; 28 if(p<=m) update(p,v,lson); 29 else update(p,v,rson); 30 for(int i=0;i<5;i++){ 31 seg[rt].mod[i]=seg[rt<<1].mod[i]+seg[rt<<1|1].mod[(i-seg[rt<<1].sz%5+5)%5]; //!! 32 } 33 seg[rt].sz=seg[rt<<1].sz+seg[rt<<1|1].sz; 34 } 35 int main(){ 36 while(scanf("%d",&n)!=EOF){ 37 CLR(b,0); 38 CLR(vis,0); 39 CLR(seg,0); 40 int i=0,k=0; 41 for(;i<n;i++){ 42 scanf("%s",s); 43 if(s[0]!='s'){ 44 scanf("%d",&b[i]); 45 a[k++]=b[i]; 46 } 47 } 48 sort(a,a+k); 49 k=unique(a,a+k)-a; //去重 50 for(int i=0;i<n;i++){ 51 if(b[i]){ 52 int p=lower_bound(a,a+k,b[i])-a; 53 vis[p]^=1; // 54 update(p,vis[p],0,k-1,1); 55 }else{ 56 printf("%lld ",seg[1].mod[2]); //因为下标从0开始,所以求余数为2的 57 } 58 } 59 } 60 return 0; 61 }
Who Gets the Most Candies?
题意: N个小孩围成一圈,他们被顺时针编号为 1 到 N。每个小孩手中有一个卡片,上面有一个非 0 的数字,游戏从第 K 个小孩开始,他告诉其他小孩他卡片上的数字并离开这个圈,他卡片上的数字 A 表明了下一个离开的小孩,如果 A 是大于 0 的,则下个离开的是左手边第 A 个,如果是小于 0 的,则是右手边的第 A 个小孩。游戏将直到所有小孩都离开,在游戏中,第 p 个离开的小孩将得到 F(p) 个糖果,F(p) 是 p 的约数的个数,问谁将得到最多的糖果。输出最幸运的小孩的名字和他可以得到的糖果。
心态崩了,,学了反素数来做这道题,,没有打表一直WA。。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int n,k; 6 //线段树 7 #define lson l,m,rt<<1 8 #define rson m+1,r,rt<<1|1 9 const int maxn=500010; 10 int sum[maxn<<2]; 11 void pushup(int rt){ 12 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 13 } 14 void build(int l,int r,int rt){ 15 if(l==r){ 16 sum[rt]=1; 17 return ; 18 } 19 int m=(l+r)>>1; 20 build(lson); 21 build(rson); 22 pushup(rt); 23 } 24 int query(int p,int l,int r,int rt){ 25 if(l==r){ 26 sum[rt]=0; 27 return l; 28 } 29 int m=(l+r)>>1; 30 int ans=0; 31 if(p<=sum[rt<<1]) ans=query(p,lson); 32 else ans=query(p-sum[rt<<1],rson); 33 pushup(rt); 34 return ans; 35 } 36 37 //反素数 38 int revpri,best; //小于n的(最小的)约数最多的数,约数 39 int pri[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,57}; 40 void dfs(int d,int ct,int temp,int num){ 41 if(d>=16) return; 42 if(num>=best||num==best&&revpri>temp){ 43 revpri=temp; 44 best=num; 45 } 46 for(int i=1;i<=ct;i++){ 47 if(n<temp*pri[d]) break; 48 dfs(d+1,i,temp*=pri[d],num*(i+1)); 49 } 50 } 51 int antiPrime[]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120, 52 20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960, 53 554400 }; 54 55 int fact[]={1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,90,96,100,108,120,128, 56 144,160,168,180,192,200,216}; 57 58 char name[maxn][12]; 59 int val[maxn]; 60 int main(){ 61 while(scanf("%d%d",&n,&k)!=EOF){ 62 build(1,n,1); 63 // revpri=1e9; 64 // best=1; 65 // dfs(0,62,1,1); 66 for(int i=0;antiPrime[i]<=n;i++){ 67 revpri=i; 68 } 69 for(int i=1;i<=n;i++){ 70 scanf("%s%d",name[i],&val[i]); 71 } 72 val[0]=0; 73 int id=0; 74 for(int i=0;i<antiPrime[revpri];i++){ 75 int mod=sum[1]; 76 if(val[id]>0){ 77 k=((k-1+val[id]-1)%mod+mod)%mod+1; 78 }else{ 79 k=((k-1+val[id])%mod+mod)%mod+1; 80 } 81 id=query(k,1,n,1); 82 } 83 printf("%s %d ",name[id],fact[revpri]); 84 } 85 }
Points
题意:可加点或者删点,找平面内严格大于(x,y)的最小点。
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct Node{ 4 int x,y; 5 bool operator<(const Node &a)const{ 6 return x<a.x&&y<a.y; 7 } 8 }; 9 set<Node> s; 10 11 int main(){ 12 int n; 13 scanf("%d",&n); 14 char ss[10]; 15 int x,y; 16 while(n--){ 17 scanf("%s%d%d",ss,&x,&y); 18 if(ss[0]=='a'){ 19 s.insert(Node{x,y}); 20 }else if(ss[0]=='r'){ 21 s.erase(s.find(Node{x,y})); 22 }else { 23 set<Node> ::iterator it; 24 it=s.upper_bound(Node{x,y}); 25 if(it!=s.end()) 26 printf("%d %d ",it->x,it->y); 27 else puts("-1"); 28 29 } 30 } 31 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 //线段树 5 const int maxn=200010; 6 #define lson l,m,rt<<1 7 #define rson m+1,r,rt<<1|1 8 int maxx[maxn<<2]; //存的是各x中y的最大值 9 void pushup(int rt){ 10 maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]); 11 } 12 13 void build(int l,int r,int rt){ 14 if(l==r){ 15 maxx[rt]=-1; 16 return ; 17 } 18 int m=(l+r)>>1; 19 build(lson); 20 build(rson); 21 // pushup(rt); 22 } 23 set<int> idy[maxn]; 24 void update(int p,int l,int r,int rt){ 25 if(l==r){ 26 if(idy[p].size()) //!! 27 maxx[rt]=*(--idy[p].end()); 28 else 29 maxx[rt]=-1; 30 return ; 31 } 32 int m=(l+r)>>1; 33 if(p<=m) update(p,lson); 34 else update(p,rson); 35 pushup(rt); 36 } 37 38 int query(int id,int y,int l,int r,int rt){ 39 if(id>=r||y>=maxx[rt]) return -1; 40 if(l==r){ 41 return l; 42 } 43 int m=(l+r)>>1; 44 int ans=-1; 45 ans=query(id,y,lson); 46 if(ans==-1) ans=query(id,y,rson); 47 return ans; 48 } 49 50 51 52 int n; 53 char s[maxn][10]; 54 int x,y; 55 int px[maxn],py[maxn]; 56 int num[maxn]; //离散化 57 int cnt=0; 58 int main(){ 59 scanf("%d",&n); 60 for(int i=1;i<=n;i++){ 61 scanf("%s%d%d",s[i],&px[i],&py[i]); 62 if(s[i][0]=='a') num[++cnt]=px[i]; 63 } 64 sort(num+1,num+1+cnt); 65 cnt=unique(num+1,num+1+cnt)-(num+1); 66 if(cnt==0){ 67 maxx[1]=-1; 68 }else { 69 build(1,cnt,1); 70 } 71 for(int i=1;i<=n;i++){ 72 int id=upper_bound(num+1,num+1+cnt,px[i])-(num+1); 73 if(s[i][0]=='a'){ 74 idy[id].insert(py[i]); 75 update(id,1,cnt,1); 76 }else if(s[i][0]=='r'){ 77 idy[id].erase(py[i]); 78 update(id,1,cnt,1); 79 }else{ 80 int ans=-1; 81 if(id<=cnt) ans=query(id,py[i],1,cnt,1); 82 if(ans==-1){ 83 puts("-1"); 84 }else { 85 printf("%d %d ",num[ans],*idy[ans].upper_bound(py[i])); 86 } 87 } 88 } 89 return 0; 90 }
Cows
题意:求每个区间被多少个区间完全覆盖。
首先将区间按x从小到大排序,x相等时按y从大到小。
这样排序的目的是让排在前面的区间左端点一定小于右端点,后面加到线段树里面时只要看有多少右端点大于当前区间。
当两个区间相同时不要重复计算,不然要分类讨论会比较麻烦。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 #define lson l,m,rt<<1 7 #define rson m+1,r,rt<<1|1 8 9 const int maxn=1e5+10; 10 int sum[maxn<<2]; 11 void pushup(int rt){ 12 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 13 } 14 void update(int p,int l,int r,int rt){ 15 if(l==r){ 16 sum[rt]++; 17 return; 18 } 19 int m=(l+r)>>1; 20 if(p<=m) update(p,lson); 21 else update(p,rson); 22 pushup(rt); 23 } 24 int query(int L,int R,int l,int r,int rt){ 25 if(L<=l&&r<=R){ 26 return sum[rt]; 27 } 28 int m=(l+r)>>1; 29 int ans=0; 30 if(L<=m) ans+=query(L,R,lson); 31 if(R>m) ans+=query(L,R,rson); 32 return ans; 33 } 34 struct Node{ 35 int s,e,id; 36 Node(int s=-1,int e=-1,int id=-1):s(s),e(e),id(id){} 37 bool operator<(const Node&a)const { 38 return s<a.s||s==a.s&&e>a.e; 39 } 40 }node[maxn]; 41 int n; 42 int res[maxn]; 43 44 int main(){ 45 while(scanf("%d",&n)!=EOF&&n){ 46 int cnt=0; 47 int s,e; 48 for(int i=0;i<n;i++){ 49 scanf("%d%d",&s,&e); 50 node[cnt++]=Node(s,e,i); 51 } 52 sort(node,node+cnt); 53 memset(sum,0,sizeof(sum)); 54 for(int i=0;i<n;i++){ 55 if(i!=0&&node[i-1].s==node[i].s&&node[i-1].e==node[i].e){ 56 res[node[i].id]=res[node[i-1].id]; 57 }else res[node[i].id]=query(node[i].e,maxn,0,maxn,1); 58 update(node[i].e,0,maxn,1); 59 } 60 for(int i=0;i<n;i++){ 61 printf("%d%c",res[i],i==n-1?' ':' '); 62 } 63 } 64 return 0; 65 }
小明系列问题——小明序列
题意:给一个数组,求间距大于k的最长上升子序列。
哎感觉自己真水,,啥也不会,之前还以为线段树都会了,现在连点更新都做不出。。。
节点保存以i结尾的间距大于k的最长上升子序列长度
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=1e5+10; 5 #define lson l,m,rt<<1 6 #define rson m+1,r,rt<<1|1 7 8 int d[maxn<<2]; //d[i]表示以i结尾的最长上升子序列长度 9 int mx[maxn]; 10 11 void pushup(int rt){ 12 d[rt]=max(d[rt<<1],d[rt<<1|1]); 13 } 14 15 void update(int p,int v,int l,int r,int rt){ 16 if(l==r){ 17 d[rt]=v; 18 return; 19 } 20 int m=(l+r)>>1; 21 if(p<=m) update(p,v,lson); 22 else update(p,v,rson); 23 pushup(rt); 24 } 25 26 int query(int L,int R,int l,int r,int rt){ 27 if(L<=l&&r<=R) return d[rt]; 28 int m=(l+r)>>1; 29 int ans=0; 30 if(L<=m) ans=max(ans,query(L,R,lson)); 31 if(R>m) ans=max(ans,query(L,R,rson)); 32 return ans; 33 } 34 int a[maxn]; 35 int main(){ 36 int n,k; 37 while(scanf("%d%d",&n,&k)!=EOF){ 38 int maxx=0; 39 for(int i=0;i<n;i++){ 40 scanf("%d",&a[i]); 41 maxx=max(maxx,a[i]); 42 } 43 memset(d,0,sizeof(d)); 44 int ans=0; 45 for(int i=0;i<n;i++){ 46 if(i-k-1>=0) update(a[i-k-1],mx[i-k-1],0,maxx,1); //把i前面d位的数加进去 47 if(a[i]>0) mx[i]=query(0,a[i]-1,0,maxx,1)+1; 48 else mx[i]=1; 49 ans=max(ans,mx[i]); 50 } 51 printf("%d ",ans); 52 } 53 }
Mushroom Gnomes - 2
题意:给出n棵树的位置a和高度h,往左倒的概率pl,往右倒的高度pr。给出m棵蘑菇的位置和魔力值。求剩余蘑菇的魔力值的期望。
离散化+区间更新+单点查询
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 const int maxn=1e5+10; 6 7 double pro[maxn<<4]; 8 int lazy[maxn<<4]; 9 10 int c[maxn<<2]; 11 int b[maxn],magic[maxn]; 12 double pl[maxn],pr[maxn]; 13 int a[maxn],h[maxn]; 14 15 void pushdown(int rt){ 16 if(lazy[rt]){ 17 lazy[rt<<1]=lazy[rt<<1|1]=1; 18 pro[rt<<1]*=pro[rt]; 19 pro[rt<<1|1]*=pro[rt]; 20 pro[rt]=1.0; 21 lazy[rt]=0; 22 } 23 } 24 25 void build(int l,int r,int rt){ 26 pro[rt]=1.0; 27 lazy[rt]=0; 28 if(l==r){ 29 30 return ; 31 } 32 int m=(l+r)>>1; 33 build(lson); 34 build(rson); 35 } 36 37 void update(int L,int R,double p,int l,int r,int rt){ 38 if(L<=l&&r<=R){ 39 pro[rt]*=(double)p; 40 lazy[rt]=1; 41 return ; 42 } 43 int m=(l+r)>>1; 44 pushdown(rt); 45 if(L<=m) update(L,R,p,lson); 46 if(R>m) update(L,R,p,rson); 47 } 48 49 double query(int p,int l,int r,int rt){ 50 if(l==r){ 51 return pro[rt]; 52 } 53 pushdown(rt); 54 int m=(l+r)>>1; 55 if(p<=m) return query(p,lson); 56 else return query(p,rson); 57 } 58 59 int main(){ 60 int n,m; 61 scanf("%d%d",&n,&m); 62 int cnt=0; 63 for(int i=0;i<n;i++){ 64 scanf("%d%d%lf%lf",&a[i],&h[i],&pl[i],&pr[i]); 65 pl[i]/=100.0; 66 pr[i]/=100.0; 67 c[cnt++]=a[i]; 68 c[cnt++]=a[i]-h[i]; 69 c[cnt++]=a[i]+h[i]; 70 } 71 for(int i=0;i<m;i++){ 72 scanf("%d%d",&b[i],&magic[i]); 73 c[cnt++]=b[i]; 74 } 75 sort(c,c+cnt); 76 cnt=unique(c,c+cnt)-c; 77 build(0,cnt-1,1); 78 for(int i=0;i<n;i++){ 79 int L=lower_bound(c,c+cnt,a[i]-h[i])-c; 80 int R=lower_bound(c,c+cnt,a[i]+h[i])-c; 81 int M=lower_bound(c,c+cnt,a[i])-c; 82 update(L,M-1,1.0-pl[i],0,cnt-1,1); 83 update(M+1,R,1.0-pr[i],0,cnt-1,1); 84 } 85 86 double ans=0.0; 87 for(int i=0;i<m;i++){ 88 int p=lower_bound(c,c+cnt,b[i])-c; 89 ans+=query(p,0,cnt-1,1)*magic[i]; 90 } 91 printf("%lf ",ans); 92 }
Subpalindromes
题意:判断字符串在[a,b]区间内是不是回文串。支持单点修改字符串。
当字符串左hash值和右hash值相等时极有可能是回文串,用线段树维护左hash值和右hash值。
pushup操作很关键。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ull unsigned long long 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 const int maxn=100010; 7 const int seed=31; 8 ull base[maxn]; 9 struct Node{ 10 ull lv,rv; 11 }node[maxn<<2]; 12 char s[maxn]; 13 void pushup(int L,int R,int rt){ 14 node[rt].lv=node[rt<<1].lv+node[rt<<1|1].lv*base[L]; 15 node[rt].rv=node[rt<<1].rv*base[R]+node[rt<<1|1].rv; 16 } 17 void build(int l,int r,int rt){ 18 if(l==r){ 19 node[rt].lv=node[rt].rv=s[l]; 20 return; 21 } 22 int m=(l+r)>>1; 23 build(lson); 24 build(rson); 25 pushup(m-l+1,r-m,rt); 26 } 27 void update(int p,char a,int l,int r,int rt){ 28 if(l==r){ 29 node[rt].lv=node[rt].rv=a; 30 return ; 31 } 32 int m=(l+r)>>1; 33 if(p<=m) update(p,a,lson); 34 else update(p,a,rson); 35 pushup(m-l+1,r-m,rt); 36 } 37 Node query(int L,int R,int l,int r,int rt){ 38 if(L<=l&&r<=R) return node[rt]; 39 int m=(l+r)>>1; 40 if(R<=m) return query(L,R,lson); 41 if(L>m) return query(L,R,rson); 42 Node ans1=query(L,R,lson); 43 Node ans2=query(L,R,rson); 44 Node ans; 45 ans.lv=ans1.lv+ans2.lv*base[m-max(l,L)+1]; 46 ans.rv=ans1.rv*base[min(r,R)-m]+ans2.rv; 47 return ans; 48 } 49 int main(){ 50 base[0]=1; 51 for(int i=1;i<maxn;i++) base[i]=base[i-1]*seed; 52 while(scanf("%s",s+1)!=EOF){ 53 s[0]='0'; 54 int n=strlen(s)-1; 55 build(1,n,1); 56 int m; 57 scanf("%d",&m); 58 while(m--){ 59 char op[20],c; 60 int a,b; 61 scanf("%s",op); 62 if(op[0]=='c'){ 63 scanf("%d %c",&a,&c); 64 update(a,c,1,n,1); 65 }else { 66 scanf("%d%d",&a,&b); 67 Node ans=query(a,b,1,n,1); 68 if(ans.lv==ans.rv) puts("Yes"); 69 else puts("No"); 70 } 71 } 72 } 73 return 0; 74 }
Parking Log
题意:有T组测试数据,每组数据的N和Q分别表示停车场有N个位置(下标从1开始),Q个操作。操作有两种(1)"A M L R",表示这个车队有M辆车,如果前面的空位,要求与前面的车的距离不超过L,如果后面有车,要求与后面的车的距离不超过R,如果前面或后面没有车,条件L,R的限制忽略,如果有满足条件的位置输出起点的下标,如果有多个满足条件的位置输出下标最小的一个,如果没有满足条件的位置,输出-1。(2)"BK",表示从左到右数第k个车队离开。
待补题~~
成段更新
Just a Hook
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 const int maxn=100010; 7 ll add[maxn<<2]; 8 ll sum[maxn<<2]; 9 10 11 void pushup(int rt){ 12 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 13 } 14 void pushdown(int rt,int m){ 15 if(add[rt]){ 16 add[rt<<1]=add[rt]; 17 add[rt<<1|1]=add[rt]; 18 sum[rt<<1]=add[rt]*(m>>1); 19 sum[rt<<1|1]=add[rt]*(m-(m>>1)); 20 add[rt]=0; 21 } 22 } 23 24 void build(int l,int r,int rt){ 25 add[rt]=0; 26 if(l==r){ 27 sum[rt]=1; 28 return; 29 } 30 int m=(l+r)>>1; 31 build(lson); 32 build(rson); 33 pushup(rt); 34 } 35 36 void update(int L,int R,int c,int l,int r,int rt){ 37 if(L<=l&&r<=R){ 38 add[rt]=c; 39 sum[rt]=(ll)c*(r-l+1); 40 return ; 41 } 42 pushdown(rt,r-l+1); 43 int m=(l+r)>>1; 44 if(L<=m) update(L,R,c,lson); 45 if(R>m) update(L,R,c,rson); 46 pushup(rt); 47 } 48 49 ll query(int L,int R,int l,int r,int rt){ 50 if(L<=l&&r<=R) 51 { 52 return sum[rt]; 53 } 54 pushdown(rt,r-l+1); 55 ll ans=0; 56 int m=(l+r)>>1; 57 if(L<=m) ans+=query(L,R,lson); 58 if(R>m) ans+=query(L,R,rson); 59 return ans; 60 } 61 62 int main(){ 63 int n,m; 64 int t; 65 scanf("%d",&t); 66 for(int i=1;i<=t;i++){ 67 scanf("%d%d",&n,&m); 68 build(1,n,1); 69 while(m--){ 70 int a,b,c; 71 scanf("%d%d%d",&a,&b,&c); 72 update(a,b,c,1,n,1); 73 } 74 printf("Case %d: The total value of the hook is %lld. ",i,query(1,n,1,n,1)); 75 } 76 return 0; 77 }
A Simple Problem with Integers
1 #include<cstdio> 2 #define lson l,m,rt<<1 3 #define rson m+1,r,rt<<1|1 4 #define ll long long 5 const int maxn=100010; 6 ll f[maxn<<2]; 7 ll add[maxn<<2]; 8 inline void pushup(int rt) 9 { 10 f[rt]=f[rt<<1]+f[rt<<1|1]; 11 } 12 void build(int l,int r,int rt) 13 { 14 add[rt]=0; 15 if(l==r) 16 { 17 scanf("%lld",&f[rt]); 18 return; 19 } 20 int m=(l+r)>>1; 21 build(lson); 22 build(rson); 23 pushup(rt); 24 } 25 26 void pushdown(int rt,int m) 27 { 28 if(add[rt]) 29 { 30 add[rt<<1]+=add[rt]; 31 add[rt<<1|1]+=add[rt]; 32 f[rt<<1]+=(m-(m>>1))*add[rt]; 33 f[rt<<1|1]+=(m>>1)*add[rt]; 34 add[rt]=0; 35 } 36 } 37 void update(int L,int R,int c,int l,int r,int rt) 38 { 39 if(L<=l&&r<=R) { 40 add[rt]+=c; 41 f[rt]+=(ll)c*(r-l+1); 42 return; 43 } 44 pushdown(rt,r-l+1); 45 int m=(l+r)>>1; 46 if(L<=m) update(L,R,c,lson); 47 if(R>m) update(L,R,c,rson); 48 pushup(rt); 49 } 50 ll query(int L,int R,int l,int r,int rt) 51 { 52 if(L<=l&&r<=R) return f[rt]; 53 54 pushdown(rt,r-l+1); 55 int m=(l+r)>>1; 56 ll ans=0; 57 if(L<=m) ans+=query(L,R,lson); 58 if(R>m) ans+=query(L,R,rson); 59 return ans; 60 } 61 62 int main() 63 { 64 int n,m; 65 int a,b,c; 66 while(scanf("%d%d",&n,&m)!=EOF) 67 { 68 build(1,n,1); 69 while(m--) 70 { 71 char s[2]; 72 scanf("%s",s); 73 if(s[0]=='Q') 74 { 75 scanf("%d%d",&a,&b); 76 printf("%lld ",query(a,b,1,n,1)); 77 } 78 else { 79 scanf("%d%d%d",&a,&b,&c); 80 update(a,b,c,1,n,1); 81 } 82 } 83 84 } 85 return 0; 86 }
Mayor's posters
这道大概是我纠结时间最久的一道题了。。。一波三折~
就一句话:此线段非彼线段。
其实POJ构造的数轴是这样的 |___|___|___|___|___|___|___|___| 1 2 3 4 5 6 7 8 而质疑数据的你们构造的数轴是这样的: |___|___|___|___|___|___|___| 1 2 3 4 5 6 7 8
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=100010; 7 int f[maxn<<4]; 8 #define lson l,m,rt<<1 9 #define rson m+1,r,rt<<1|1 10 int li[maxn],ri[maxn]; 11 int X[maxn<<3]; 12 int has[maxn]; 13 int n,lo; 14 int ct=0; 15 int ans=0; 16 17 18 void pushdown(int rt) 19 { 20 if(f[rt]!=-1) 21 { 22 f[rt<<1|1]=f[rt<<1]=f[rt]; 23 f[rt]=-1; 24 } 25 } 26 27 void update(int L,int R,int id,int l,int r,int rt) 28 { 29 if(L<=l&&r<=R) 30 { 31 f[rt]=id; 32 return; 33 } 34 int m=(l+r)>>1; 35 pushdown(rt); 36 if(L<=m) update(L,R,id,lson); //连续 37 if(R>m) update(L,R,id,rson); 38 } 39 void query(int l,int r,int rt) 40 { 41 if(f[rt]!=-1) 42 { 43 if(!has[f[rt]]) ans++; 44 has[f[rt]]=1; 45 return; 46 } 47 if(l==r) return; //连续区间的返回条件 48 int m=(l+r)>>1; 49 query(lson); 50 query(rson); 51 } 52 53 int Bin(int x,int len,int *X) 54 { 55 int l=0,r=len; 56 while(l<=r) 57 { 58 int m=(l+r)>>1; 59 if(X[m]==x) return m; 60 if(X[m]>x) r=m-1; 61 else l=m+1; 62 } 63 return -1; 64 } 65 int main() 66 { 67 int t; 68 scanf("%d",&t); 69 while(t--){ 70 scanf("%d",&n); 71 for(int i=0;i<n;i++) 72 { 73 scanf("%d%d",&li[i],&ri[i]); 74 X[ct++]=li[i]; 75 X[ct++]=ri[i]; 76 } 77 sort(X,X+ct); 78 int m=1; 79 for(int i=1;i<ct;i++) if(X[i]!=X[i-1]) X[m++]=X[i]; //离散化 80 m--; 81 memset(f,-1,sizeof(f)); 82 for(int i=0;i<n;i++) 83 { 84 int L=Bin(li[i],m,X); 85 int R=Bin(ri[i],m,X); 86 update(L,R,i,0,m,1); 87 } 88 memset(has,0,sizeof(has)); 89 ans=0; 90 query(0,m,1); 91 printf("%d ",ans); 92 } 93 }
Crane
题意:一些起重臂编号1到n,开始时竖直相连,每次操作把id到n的起重臂逆时针旋转agl度,问第n个起重臂的坐标(末尾)。
很好的一道题。
节点信息是各点的坐标(不同坐标系)。
首先,用到了坐标系变换,参考坐标系为该节点的上一个节点,于是满足了区间可加性,所有点加起来就是n的坐标了。
其次,本题用的是左手坐标系,x轴水平向右,y轴竖直向下,这就导致了旋转时坐标的计算和左手坐标系不同,简言之就是逆时针变成了顺时针。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 using namespace std; 5 #define lson l,m,rt<<1 6 #define rson m+1,r,rt<<1|1 7 const int maxn=10010; 8 const double pi=acos(-1.0); 9 int add[maxn<<2]; 10 double x[maxn<<2],y[maxn<<2]; 11 int deg[maxn]; 12 13 void pushup(int rt){ 14 x[rt]=x[rt<<1]+x[rt<<1|1]; 15 y[rt]=y[rt<<1]+y[rt<<1|1]; 16 } 17 void build(int l,int r,int rt){ 18 add[rt]=0; 19 if(l==r){ 20 scanf("%lf",&y[rt]); 21 x[rt]=0.0; 22 deg[l]=180;//deg[l]是两个起重臂L和L+1的夹角 23 return ; 24 } 25 int m=(l+r)>>1; 26 build(lson); 27 build(rson); 28 pushup(rt); 29 30 } 31 void rotate(int rt,int g){ 32 double gg=g/180.0*pi; 33 //顺时针 34 double tempx=x[rt]*cos(gg)+y[rt]*sin(gg); 35 double tempy=y[rt]*cos(gg)-x[rt]*sin(gg); 36 x[rt]=tempx; 37 y[rt]=tempy; 38 } 39 void pushdown(int rt){ 40 if(add[rt]){ 41 add[rt<<1]+=add[rt]; 42 add[rt<<1|1]+=add[rt]; 43 rotate(rt<<1,add[rt]); 44 rotate(rt<<1|1,add[rt]); 45 add[rt]=0; 46 } 47 } 48 void update(int L,int R,int g,int l,int r,int rt){ 49 if(L<=l&&r<=R){ 50 add[rt]+=g; 51 rotate(rt,g); 52 return; 53 } 54 int m=(l+r)>>1; 55 pushdown(rt); 56 if(L<=m) update(L,R,g,lson); 57 if(R>m) update(L,R,g,rson); 58 pushup(rt); 59 } 60 int main(){ 61 int n,m; 62 int kase=0; 63 while(scanf("%d%d",&n,&m)!=EOF){ 64 if(kase++) puts(""); 65 build(1,n,1); 66 int id,agl; 67 while(m--){ 68 scanf("%d%d",&id,&agl); 69 update(id+1,n,deg[id]-agl,1,n,1); //deg[id]-agl是需要旋转的角度 70 deg[id]=agl; //跟新两个起重臂的夹角 71 printf("%.2f %.2f ",x[1],y[1]); 72 } 73 74 } 75 }
Another LCIS
题意:可区间更新,并求指定区间最长上升子序列的长度。
应该是区间合并的题了,之前接触比较少,做起来还是有点难。。。
一个区间的最长上升子序列有三种情况,max(跨越中间(左二子后缀+右儿子前缀)最长,max(左二子的最长,右儿子的最长))
为了支持区间加法,除了维护三个(左、右、全)最长外,还要维护各区间的左值和右值,以便更新,具体细节看代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 #define lson l,m,rt<<1 6 #define rson m+1,r,rt<<1|1 7 const int maxn=100010; 8 int Lm[maxn<<2],Rm[maxn<<2],lv[maxn<<2],rv[maxn<<2],maxx[maxn<<2]; 9 int add[maxn<<2]; 10 void pushup(int l,int r,int rt){ 11 lv[rt]=lv[rt<<1]; 12 rv[rt]=rv[rt<<1|1]; 13 Lm[rt]=Lm[rt<<1];Rm[rt]=Rm[rt<<1|1];maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]); 14 if(rv[rt<<1]<lv[rt<<1|1]){ 15 int len=r-l+1; 16 if(Lm[rt<<1]==len-(len>>1)) Lm[rt]+=Lm[rt<<1|1]; //!!! 17 if(Rm[rt<<1|1]==len>>1) Rm[rt]+=Rm[rt<<1]; //!!! 18 maxx[rt]=max(maxx[rt],Rm[rt<<1]+Lm[rt<<1|1]); 19 } 20 maxx[rt]=max(maxx[rt],max(Lm[rt],Rm[rt])); 21 } 22 23 void build(int l,int r,int rt){ 24 add[rt]=0; 25 if(l==r){ 26 scanf("%d",&lv[rt]); 27 rv[rt]=lv[rt]; 28 Lm[rt]=Rm[rt]=maxx[rt]=1; 29 return ; 30 } 31 int m=(l+r)>>1; 32 build(lson); 33 build(rson); 34 pushup(l,r,rt); 35 } 36 void pushdown(int rt){ 37 if(add[rt]){ 38 add[rt<<1]+=add[rt]; 39 add[rt<<1|1]+=add[rt]; 40 lv[rt<<1]+=add[rt]; 41 rv[rt<<1]+=add[rt]; 42 lv[rt<<1|1]+=add[rt]; 43 rv[rt<<1|1]+=add[rt]; 44 add[rt]=0; 45 } 46 } 47 void update(int L,int R,int c,int l,int r,int rt){ 48 if(L<=l&&r<=R){ 49 add[rt]+=c; 50 lv[rt]+=c;rv[rt]+=c; 51 return ; 52 } 53 pushdown(rt); 54 int m=(l+r)>>1; 55 if(L<=m) update(L,R,c,lson); 56 if(R>m) update(L,R,c,rson); 57 pushup(l,r,rt); 58 } 59 int query(int L,int R,int l,int r,int rt){ 60 if(L<=l&&r<=R){ 61 return maxx[rt]; 62 } 63 pushdown(rt); 64 int m=(l+r)>>1; 65 if(R<=m) return query(L,R,lson); 66 if(L>m) return query(L,R,rson); 67 int ans1= query(L,R,lson); 68 int ans2= query(L,R,rson); 69 int ans=max(ans1,ans2); 70 if(rv[rt<<1]<lv[rt<<1|1]){ 71 int temp1=min(m-L+1,Rm[rt<<1]); 72 int temp2=min(R-m,Lm[rt<<1|1]); 73 ans=max(ans,temp1+temp2); 74 } 75 return ans; 76 } 77 int main(){ 78 int t,kase=0; 79 scanf("%d",&t); 80 int n,m; 81 while(t--){ 82 printf("Case #%d: ",++kase); 83 scanf("%d%d",&n,&m); 84 build(1,n,1); 85 char s[3]; 86 int a,b,c; 87 while(m--){ 88 scanf("%s",s); 89 if(s[0]=='a'){ 90 scanf("%d%d%d",&a,&b,&c); 91 update(a,b,c,1,n,1); 92 }else{ 93 scanf("%d%d",&a,&b); 94 printf("%d ",query(a,b,1,n,1)); 95 } 96 } 97 } 98 return 0; 99 }
Bracket Sequence
题意:问指定区间内括号是否匹配。
把左括号设为-1,右括号设为1,那么一个区间的括号匹配的充要条件是这个区间的前缀和最大值小于等于0,区间和等于0。
因为有两种操作,一是反转(rev)指定区间的括号,二是重置(set)指定区间的括号,为了满足区间加法,还要维护一个区间前缀和最小值。
如果需要函数返回两个值,可以返回结构体,也可以用引用传参的方法。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 const int maxn=110010; 6 int sum[maxn<<2],minv[maxn<<2],maxv[maxn<<2]; 7 int rev[maxn<<2],set_[maxn<<2]; 8 char str[maxn]; 9 void pushup(int rt){ 10 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 11 minv[rt]=min(minv[rt<<1],sum[rt<<1]+minv[rt<<1|1]); 12 maxv[rt]=max(maxv[rt<<1],sum[rt<<1]+maxv[rt<<1|1]); 13 } 14 15 void build(int l,int r,int rt){ 16 set_[rt]=rev[rt]=0; 17 if(l==r){ 18 sum[rt]=str[l]=='('?-1:1; 19 minv[rt]=min(0,sum[rt]); 20 maxv[rt]=max(0,sum[rt]); 21 return ; 22 } 23 int m=(l+r)>>1; 24 build(lson); 25 build(rson); 26 pushup(rt); 27 } 28 void set_val(int rt,int len,int val){ 29 sum[rt]=val*len; 30 minv[rt]=min(0,val*len); 31 maxv[rt]=max(0,val*len); 32 set_[rt]=val; 33 rev[rt]=0; 34 } 35 void rev_val(int rt){ 36 sum[rt]=-sum[rt]; 37 minv[rt]=-minv[rt]; 38 maxv[rt]=-maxv[rt]; 39 swap(minv[rt],maxv[rt]); 40 rev[rt]^=1; 41 } 42 void pushdown(int rt,int len){ 43 if(set_[rt]!=0){ 44 set_val(rt<<1,len-(len>>1),set_[rt]); 45 set_val(rt<<1|1,len>>1,set_[rt]); 46 set_[rt]=0; 47 } 48 if(rev[rt]){ 49 rev_val(rt<<1); 50 rev_val(rt<<1|1); 51 rev[rt]=0; 52 } 53 } 54 void update(int L,int R,int val,int l,int r,int rt){ 55 if(L<=l&&r<=R){ 56 if(val==2){ 57 rev_val(rt); 58 }else { 59 int len=r-l+1; 60 set_val(rt,len,val); 61 } 62 return ; 63 } 64 pushdown(rt,r-l+1); 65 int m=(l+r)>>1; 66 if(L<=m) update(L,R,val,lson); 67 if(R>m) update(L,R,val,rson); 68 pushup(rt); 69 } 70 void query(int L,int R,int &a,int &b,int l,int r,int rt){ 71 if(L<=l&&r<=R){ 72 a=maxv[rt]; 73 b=sum[rt]; 74 return ; 75 } 76 pushdown(rt,r-l+1); 77 int m=(l+r)>>1; 78 int a1=0,b1=0,a2=0,b2=0; 79 if(L<=m) query(L,R,a1,b1,lson); 80 if(R>m) query(L,R,a2,b2,rson); 81 a=max(a1,b1+a2); 82 b=b1+b2; 83 return ; 84 } 85 int n,m; 86 char s[10]; 87 88 int main(){ 89 int t,kase=0; 90 scanf("%d",&t); 91 while(t--){ 92 93 scanf("%d%s%d",&n,str+1,&m); 94 printf("Case %d: ",++kase); 95 build(1,n,1); 96 while(m--){ 97 int x,y; 98 scanf("%s%d%d",s,&x,&y); 99 x++;y++; 100 if(s[0]=='q'){ 101 int a,b; 102 query(x,y,a,b,1,n,1); 103 if(a<=0&&b==0) puts("YES"); 104 else puts("NO"); 105 }else if(s[0]=='s'){ 106 scanf("%s",s); 107 int val=s[0]=='('?-1:1; 108 update(x,y,val,1,n,1); 109 }else if(s[0]=='r'){ 110 update(x,y,2,1,n,1); 111 } 112 } 113 puts(""); 114 } 115 return 0; 116 }
Little Elephant and Array
题意:问给定区间有多少个x出现了x次。
第一种方法:暴力
因为根据数据范围x的个数不会超过500,f[i][j]表示v[i]在j之前出现了几次
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=100010; 5 6 int a[maxn]; 7 map<int,int> cnt; 8 vector<int> v; 9 int f[550][maxn]; 10 11 int main(){ 12 int n,m; 13 scanf("%d%d",&n,&m); 14 for(int i=1;i<=n;i++){ 15 scanf("%d",&a[i]); 16 cnt[a[i]]++; 17 if(cnt[a[i]]==a[i]) v.push_back(a[i]); 18 } 19 for(int i=0;i<v.size();i++) 20 for(int j=1;j<=n;j++){ 21 f[i][j]=f[i][j-1]+(v[i]==a[j]); 22 } 23 while(m--){ 24 int x,y; 25 scanf("%d%d",&x,&y); 26 int ans=0; 27 for(int i=0;i<v.size();i++){ 28 if(f[i][y]-f[i][x-1]==v[i]) ans++; 29 } 30 printf("%d ",ans); 31 } 32 return 0; 33 }
稍微优化一下快了很多,当某个数出现的总次数小于自己时,不再考虑这个数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=100010; 5 6 int a[maxn],cnt[maxn],L[maxn],R[maxn]; 7 int s[maxn],ans[maxn]; 8 9 int main(){ 10 int n,m; 11 scanf("%d%d",&n,&m); 12 for(int i=1;i<=n;i++){ 13 scanf("%d",&a[i]); 14 if(a[i]<=n) cnt[a[i]]++; 15 } 16 17 for(int i=0;i<m;i++){ 18 scanf("%d%d",&L[i],&R[i]); 19 } 20 21 for(int i=1;i<=n;i++)if(i<=cnt[i]){ 22 for(int j=1;j<=n;j++){ 23 s[j]=s[j-1]+(a[j]==i); 24 } 25 for(int j=0;j<m;j++){ 26 if(s[R[j]]-s[L[j]-1]==i) ans[j]++; 27 } 28 } 29 for(int i=0;i<m;i++) 30 printf("%d ",ans[i]); 31 }
第二种方法:线段树
待补~
Mex
题意:求所有区间的mex和。mex值为没有在该区间出现过的最小非负整数。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int maxn=200010; 6 #define CLR(m,a) memset(m,a,sizeof(m)) 7 #define ll long long 8 #define lson l,m,rt<<1 9 #define rson m+1,r,rt<<1|1 10 int maxmex[maxn<<2],_set[maxn<<2]; 11 ll sum[maxn<<2]; 12 13 int mex[maxn],vis[maxn]; 14 int pre[maxn],nex[maxn]; 15 int a[maxn]; 16 17 void pushup(int rt){ 18 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 19 maxmex[rt]=max(maxmex[rt<<1],maxmex[rt<<1|1]); 20 } 21 void build(int l,int r,int rt){ 22 _set[rt]=0; 23 if(l==r){ 24 sum[rt]=maxmex[rt]=mex[l]; 25 return ; 26 } 27 int m=(l+r)>>1; 28 build(lson); 29 build(rson); 30 pushup(rt); 31 } 32 void pushdown(int rt,int len){ 33 if(_set[rt]){ 34 _set[rt<<1]=_set[rt<<1|1]=1; 35 sum[rt<<1]=maxmex[rt]*1ll*(len-(len>>1)); 36 sum[rt<<1|1]=maxmex[rt]*1ll*(len>>1); 37 maxmex[rt<<1]=maxmex[rt<<1|1]=maxmex[rt]; 38 _set[rt]=0; 39 } 40 } 41 void update(int L,int R,int v,int l,int r,int rt){ 42 if(L<=l&&r<=R){ 43 _set[rt]=1; 44 sum[rt]=1ll*(r-l+1)*v; 45 maxmex[rt]=v; 46 return ; 47 } 48 pushdown(rt,r-l+1); 49 int m=(l+r)>>1; 50 if(L<=m) update(L,R,v,lson); 51 if(R>m) update(L,R,v,rson); 52 pushup(rt); 53 } 54 55 int query(int x,int l,int r,int rt){ 56 if(l==r){ 57 return l; 58 } 59 pushdown(rt,r-l+1); 60 int m=(l+r)>>1; 61 int ans; 62 if(x<maxmex[rt<<1]) ans=query(x,lson); 63 else ans=query(x,rson); 64 return ans; 65 } 66 67 68 int main(){ 69 int n; 70 while(scanf("%d",&n)!=EOF&&n){ 71 CLR(vis,0); 72 int k=0; //没有这个优化就会超时,,差距甚大!!! 73 for(int i=1;i<=n;i++){ 74 scanf("%d",&a[i]); 75 if(a[i]<=n) vis[a[i]]=1; 76 for(int j=k;j<=n;j++)if(!vis[j]){ 77 mex[i]=j; 78 k=j; 79 break; 80 } 81 } 82 CLR(pre,0); 83 for(int i=n;i>0;i--){ 84 if(a[i]>n) nex[i]=n+1; 85 else if(pre[a[i]]==0){ 86 pre[a[i]]=i; 87 nex[i]=n+1; 88 }else { 89 nex[i]=pre[a[i]]; 90 pre[a[i]]=i; 91 } 92 } 93 // for(int i=1;i<=n;i++) printf("%d ",nex[i]);puts(""); 94 build(1,n,1); 95 ll ans=sum[1]; 96 for(int i=1;i<=n;i++){ 97 update(i,i,0,1,n,1); 98 if(maxmex[1]>a[i]){ 99 int pos=query(a[i],1,n,1); 100 if(pos<nex[i]) update(pos,nex[i]-1,a[i],1,n,1); 101 } 102 ans+=sum[1]; 103 } 104 printf("%lld ",ans); 105 } 106 return 0; 107 }