标签:using scanf hand one lin 开始 oid 插入 none
题意
模拟栈操作。有三种操作push,pop,peak分别代表从栈顶压入元素,删除栈顶元素,查询栈顶元素。但是,每个操作会给出一个时间戳,要求操作必须要按照时间戳来进行。但是对于每个peak必须马上给出查询结果。其中n<=50000,xi,ti<=1e9
分析
讲真,这种题必须结合样例才能明白让干嘛。如果暴力的话,对于每个peak的时间复杂度都是O(n)。所以我们想到了线段树。
1.因为t的值很大,所以我们要首先将t离散化(我因为离散化写丑了一开始还T了好几发)
2.将每个push的t和x对应的记录下来
3.对于每个操作push,我们在t的位置插入1,对于每个pop操作,我们在t的位置插入-1。对于每个peak操作,我们找到t左边的第一个t1,符合sum(t1 to t)>0,这时候和t1对应的x值就是答案。
思路是很好想的,然后就是操作3该怎么通过线段树来维护?
我们通过线段树来维护一个区间和,和一个最大后缀和,然后对于没个peak查询,所有从1到t的线段树的结点,从右往左找,如果加上当前结点的最大后缀和大于0的话,这个答案就一定在这个节点内,否则加上这个结点的区间和继续往左找。这里可以结合代码进行理解。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <map> 7 8 using namespace std; 9 const int maxn=50000+100; 10 struct Ope{ 11 string name; 12 int t,a; 13 }ope[maxn]; 14 int n,kase; 15 int V[maxn],M[maxn]; 16 int sumv[4*maxn],max_suff[4*maxn]; 17 int v,x; 18 void maintain(int o){ 19 sumv[o]=sumv[2*o]+sumv[2*o+1]; 20 max_suff[o]=max(max_suff[2*o+1],sumv[2*o+1]+max_suff[2*o]); 21 } 22 void update(int o,int L,int R){ 23 if(L==R){ 24 sumv[o]+=x; 25 max_suff[o]+=x; 26 return ; 27 } 28 int M=L+(R-L)/2; 29 if(v<=M)update(2*o,L,M); 30 if(v>M)update(2*o+1,M+1,R); 31 maintain(o); 32 return; 33 } 34 int tot,ans; 35 int ql,qr; 36 void solve(int o,int L,int R){ 37 if(L==R){ 38 ans=L; 39 return; 40 } 41 int M=L+(R-L)/2; 42 if(tot+max_suff[2*o+1]>0) 43 return solve(2*o+1,M+1,R); 44 tot+=sumv[2*o+1]; 45 return solve(2*o,L,M); 46 } 47 void query(int o,int L,int R){ 48 if(ans!=-1) 49 return; 50 if(ql<=L&&qr>=R){ 51 if(tot+max_suff[o]>0){ 52 solve(o,L,R); 53 } 54 else tot+=sumv[o]; 55 return; 56 } 57 int M=L+(R-L)/2; 58 if(M<qr) 59 query(2*o+1,M+1,R); 60 if(M>=ql) 61 query(2*o,L,M); 62 return; 63 } 64 int main(){ 65 kase=0; 66 while(scanf("%d",&n)!=EOF&&n){ 67 printf("Case #%d:\n",++kase); 68 for(int i=1;i<=n;i++){ 69 cin>>ope[i].name; 70 if(ope[i].name=="push"){ 71 scanf("%d%d",&ope[i].a,&ope[i].t); 72 } 73 if(ope[i].name=="pop"||ope[i].name=="peak"){ 74 scanf("%d",&ope[i].t); 75 } 76 V[i]=ope[i].t; 77 } 78 sort(V+1,V+1+n); 79 for(int i=1;i<=n;i++){ 80 if(ope[i].name=="push"){ 81 int tt=lower_bound(V+1,V+1+n,ope[i].t)-V; 82 M[tt]=ope[i].a; 83 } 84 } 85 /* for(int i=1;i<=n;i++){ 86 int tt=lower_bound(V+1,V+1+n,ope[i].t)-V; 87 cout<<tt<<endl; 88 }*/ 89 90 memset(sumv,0,sizeof(sumv)); 91 memset(max_suff,0,sizeof(max_suff)); 92 93 for(int i=1;i<=n;i++){ 94 if(ope[i].name=="push"){ 95 v=lower_bound(V+1,V+1+n,ope[i].t)-V; 96 x=1; 97 update(1,1,n); 98 } 99 else if(ope[i].name=="pop"){ 100 v=lower_bound(V+1,V+1+n,ope[i].t)-V; 101 x=-1; 102 update(1,1,n); 103 } 104 else{ 105 ql=1,qr=lower_bound(V+1,V+1+n,ope[i].t)-V; 106 tot=0,ans=-1; 107 query(1,1,n); 108 printf("%d\n",ans==-1?-1:M[ans]); 109 } 110 } 111 } 112 return 0; 113 }
标签:using scanf hand one lin 开始 oid 插入 none
原文地址:https://www.cnblogs.com/LQLlulu/p/9011681.html