标签:线段树
链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4736
题意:有最多10000次操作,在一个初始为空的数列中添加或移除元素并保持数列有序,每次操作后,如果数列个数为奇数就输出中间值,如果为偶数就输出中间两个值得平均值。
思路:刚开始写了一发multiset模拟,看吴琦TLE了估计他也是multiset写的,就放弃这个思路了,不过最后证明multiset写的机智一点这题也是能过的。线段树、树状数组都考虑了,最后还是用线段树敲了。虽然数字范围是int内,但是操作最多只有10000次,所以需要离散化。先进行离线,再进行离散化,然后建树进行操作。每个节点维护离散化后新的数组对应的下标值在数列中出现了几次。
查询的时候输入要查询数列第几个数,然后从线段树根节点开始递归判断左右子树的数字个数,如果查询的个数小于等于左子树的数字个数,则在左子树中查询,否则要查询的数字减去左子树数字的个数并在右子树中查询,如此递归直到叶子节点,返回节点值,此时返回的值是离散化数组的下标值,再输出答案就好了。
细节: 1.输出比较恶心,对于double类型不输出后导0,直接用cout是可以的,但是输出量太大可能会TLE,所以我转成字符串输出了。
2.虽然数据都在int范围内,但是相加求平均值时可能会溢出,所以用long long来存,因为这个WA了很久。
#include<cstring> #include<string> #include<fstream> #include<iostream> #include<iomanip> #include<cstdio> #include<cctype> #include<algorithm> #include<queue> #include<map> #include<set> #include<vector> #include<stack> #include<ctime> #include<cstdlib> #include<functional> #include<cmath> using namespace std; #define PI acos(-1.0) #define MAXN 10100 #define eps 1e-7 #define INF 0x7FFFFFFF #define LLINF 0x7FFFFFFFFFFFFFFF #define seed 131 #define MOD 1000000007 #define ll long long #define ull unsigned ll #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int sum[MAXN<<2],ans[MAXN],fuck[MAXN],cha[MAXN]; int n,flag; struct node{ int num; char op; int id; }a[10100]; void pushup(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void build(int l,int r,int rt){ sum[rt] = 0; if(l==r) return ; int m = (l+r)>>1; build(lson); build(rson); } void update(int c,int x,int l,int r,int rt){ if(l==r){ if(sum[rt]==0&&x==-1){ flag = 1; return ; } sum[rt]+=x; return ; } int m = (l+r)>>1; if(c<=m) update(c,x,lson); else update(c,x,rson); pushup(rt); } int query(int c,int l,int r,int rt){ if(l==r){ return l; } //cout<<sum[rt<<1]<<" "<<l<<endl; int m = (l+r)>>1; int ret; if(sum[rt<<1]>=c){ ret = query(c,lson); } else{ ret = query(c-sum[rt<<1],rson); } return ret; } void output(double x){ int i; char ss[200]; sprintf(ss,"%lf",x); int l = strlen(ss); for(i=0;i<l;i++){ if(ss[i]=='.') break; } if(i==l){ printf("%lf\n",x); return ; } while(ss[l-1]=='0'){ l--; } if(ss[l-1]=='.') l--; for(i=0;i<l;i++){ printf("%c",ss[i]); } printf("\n"); } map<int,int>mp; int main(){ int i,j,q,t,x; char str[20]; scanf("%d",&t); while(t--){ mp.clear(); n = 0; scanf("%d",&q); for(i=1;i<=q;i++){ scanf("%s%d",str,&a[i].num); a[i].op = str[0]; a[i].id = i; fuck[i] = a[i].num; } sort(fuck+1,fuck+1+q); int p = unique(fuck+1,fuck+1+q)-fuck; for(i=1;i<p;i++){ ans[i] = fuck[i]; mp[fuck[i]] = i; } j = p; build(1,j,1); for(i=1;i<=q;i++){ if(a[i].op=='a'){ n++; update(mp[a[i].num],1,1,j,1); if(n%2){ printf("%d\n",ans[query(n/2+1,1,j,1)]); } else{ ll temp = 0; temp += ans[query(n/2,1,j,1)]; temp += ans[query(n/2+1,1,j,1)]; double t2 = temp / 2.0; //printf("%lf\n",t2); output(t2); } } else{ if(n==0){ puts("Wrong!"); continue; } flag = 0; update(mp[a[i].num],-1,1,j,1); if(flag==1){ puts("Wrong!"); continue; } n--; if(n==0){ puts("Empty!"); continue; } if(n%2){ printf("%d\n",ans[query(n/2+1,1,j,1)]); } else{ ll temp = 0; temp += ans[query(n/2,1,j,1)]; temp += ans[query(n/2+1,1,j,1)]; double t2 = temp / 2.0; //printf("%lf\n",t2); output(t2); } } } } return 0; } /* 10 a 1 a 1000000000 a 1000000000 a -1000000000 a 500 a 60000 r 1000000000 r 1 r 500 a 3000 */
标签:线段树
原文地址:http://blog.csdn.net/zzzz40/article/details/38980465