[bzoj1058][ZJOI2007]报表统计
如果算上调stl的话这题似乎有很多种做法。。。调set、map,敲线段树、spaly。。blabla
完美地避开了正解TAT
题目要求维护一坨数,能够随时插入,查询相邻的数的最小差值,查询任意两数间的最小差值。
第二问比较好写,然而人太弱不会调set。。于是写了个treap。。每次插入后查询一下前驱和后继更新一下答案。然后这个答案显然是递减的,所以数列中有相同的数之后就不用理了(大概就是市面上各种spaly能够卡时16s+过的原因。。。。)。
然而第一问就没法用treap做了。。把原数列存在map[]里面。
假设是在原数列第pos个元素后插入一个数x,那么x的右边的那个数就是map[pos+1](如果pos<n的话)
x左边的那个数其实就是本来第pos个元素后面插了一坨数的最后一个,用last[i]表示当前(插入x之前)第i个元素后面插进去的一坨数的最后一个数的大小。
所以把x插进去后,原先的差值abs(last[pos]-map[pos+1])不存在了,新增了两个差值为abs(last[pos]-x)和abs(x-map[pos+1])
用优先队列(堆)维护下差值就好了。。。。。
具体姿势:
对于新增的差值abs(last[pos]-x),它是不会被新增的数影响的。。然而abs(x-map[pos+1])可能因为之后在x后面插进去新的数而不存在。。。
判断这个差值存不存在就看x是不是所在元素的最后一次插入的数。每次查询的时候先把队头(小根堆顶)那些不存在的差值弹掉就行了。
事实证明这样写主要时间复杂度是在treap上= =。。。优先队列的速度比treap高明到不知道哪里去了。。treap的速度又比spaly高明到不知道哪里去了。。。
跑了7s+。。。。并不算快TAT
发现大部分的时间都是在treap建树的时候。。。所以直接把数列排序后递归建树(参见spaly建树姿势)就2028ms过了。。。速度#5。。
感觉第一问调set才是拯救常数的正确姿势= =
改了点细节然后1980ms#3。。。。。#1丧心病狂甩别人若干条街
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<queue> 5 #include<algorithm> 6 #include<cstdlib> 7 using namespace std; 8 const int maxn=1000003; 9 const int inf=1002333333; 10 struct zs{ 11 int pos,len,val; 12 }; 13 int num[maxn],rnd[maxn],l[maxn],r[maxn],last[maxn>>1],map[maxn>>1],len[maxn>>1]; 14 int i,j,n,m,minsg,ming,tot,rt,x,a,b,aft,pre; 15 priority_queue<zs>q; 16 bool operator <(zs a,zs b){return a.val>b.val;} 17 int ra,fh;char rx; 18 inline int read(){ 19 rx=getchar();ra=0;fh=1; 20 while((rx<'0'||rx>'9')&&rx!='-')rx=getchar(); 21 if(rx=='-')fh=-1,rx=getchar(); 22 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh; 23 } 24 char s[11]; 25 inline void outx(int x){ 26 while(x>0||!s[0])s[++s[0]]=x%10,x/=10; 27 while(s[0])putchar(s[s[0]--]+48);putchar('\n'); 28 } 29 inline void lturn(int &x,int R){r[x]=l[R],l[R]=x,x=R;} 30 inline void rturn(int &x,int L){l[x]=r[L],r[L]=x,x=L;} 31 void ins(int &x,int val){ 32 if(!x){x=++tot,num[x]=val,rnd[x]=rand();return;} 33 if(val<num[x]){ 34 ins(l[x],val); 35 if(rnd[l[x]]<rnd[x])rturn(x,l[x]); 36 }else if(val>num[x]){ 37 ins(r[x],val); 38 if(rnd[r[x]]<rnd[x])lturn(x,r[x]); 39 }else minsg=0; 40 } 41 void getpre(int now,int val){ 42 if(!now)return; 43 if(num[now]>val)getpre(l[now],val); 44 else pre=num[now],getpre(r[now],val); 45 } 46 void getaft(int now,int val){ 47 if(!now)return; 48 if(num[now]<val)getaft(r[now],val); 49 else aft=num[now],getaft(l[now],val); 50 } 51 inline void insert(int p,int x){ 52 if(minsg>0)pre=-inf,aft=inf,getpre(rt,x),getaft(rt,x),minsg=min(minsg,min(x-pre,aft-x)); 53 if(minsg>0)ins(rt,x); 54 ming=min(ming,abs(last[p]-x)); 55 len[p]++;last[p]=x; 56 if(p<n&&ming>0)q.push((zs){ p,len[p],abs(map[p+1]-x) }); 57 } 58 void build(int L,int R,int &now,int farnd){ 59 if(L>R)return; 60 int mid=(L+R+1)>>1; 61 now=++tot,num[now]=map[mid],rnd[now]=farnd+23333; 62 build(L,mid-1,l[now],rnd[now]);build(mid+1,R,r[now],rnd[now]); 63 } 64 int main(){ 65 n=read();m=read(); 66 minsg=ming=inf; 67 for(i=1;i<=n;i++)last[i]=map[i]=read(); 68 sort(map+1,map+1+n),rt=(n+1)>>1,build(1,n,rt,0); 69 for(i=1;i<n;i++)minsg=min(minsg,map[i+1]-map[i]); 70 for(i=1;i<n;i++)len[i]=1,q.push((zs){ i,len[i],abs(last[i]-last[i+1]) }); 71 memcpy(map,last,(n+1)<<2); 72 char ch1; 73 while(m--){ 74 for(ch1=getchar();ch1<'A'||ch1>'Z';ch1=getchar()); 75 if(ch1=='I') 76 a=read(),b=read(),insert(a,b); 77 else{ 78 ch1=getchar(),ch1=getchar(),ch1=getchar(),ch1=getchar(); 79 if(ch1=='S')outx(minsg); 80 else{ 81 while(q.top().len!=len[q.top().pos])q.pop(); 82 outx(min(ming,q.top().val)); 83 } 84 while(ch1!='P')ch1=getchar(); 85 } 86 } 87 return 0; 88 }