[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 }
View Code

 

posted @ 2016-01-04 21:40  czllgzmzl  阅读(...)  评论(... 编辑 收藏