题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5372
题面:
3 0 0 0 3 0 1 5 0 1 0 0 1 1 0 1 0 0
Case #1: 0 0 0 Case #2: 0 1 0 2HintFor the second case in the sample: At the first add operation,Lillian adds a segment [1,2] on the line. At the second add operation,Lillian adds a segment [0,2] on the line. At the delete operation,Lillian deletes a segment which added at the first add operation. At the third add operation,Lillian adds a segment [1,4] on the line. At the fourth add operation,Lillian adds a segment [0,4] on the line
树状数组本身并不难,但是能够用得好,想得出来怎么用还是需要很娴熟的。感觉我写的特别麻烦,T了好多次,改了快速读入,快速输出,最后才发现是有个地方写错了,G++600MS,C++1400MS,真是不懂啊。不过也算是调出来了,也算是树状数组博客第一篇吧!
代码:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #define maxn 200010 using namespace std; struct operation { //id存这是第几次操作,typ操作类型,val是操作的值 //times是第几次加操作,只对加操作有用,l,r分别是加操作的左右端点 int id; int typ; int val; int l,r; int times; }info[maxn],tmpstore[maxn]; //rgt,lft分别是树状数组的数组 int rgt[maxn],lft[maxn]; //get_sum求1到x的前缀和 int get_sum1(int x) { int res=0; while(x>0) { res+=lft[x]; x-=(x&(-x)); } return res; } int get_sum2(int x) { int res=0; while(x>0) { res+=rgt[x]; x-=(x&(-x)); } return res; } //更新x位置的值,以及其树状数组向上相关的值 void update1(int x,int val) { while(x<maxn) { lft[x]+=val; x+=(x&(-x)); } } void update2(int x,int val) { while(x<maxn) { rgt[x]+=val; x+=(x&(-x)); } } //先返回加操作早的 bool cmp1(operation a,operation b) { return a.times<b.times; } //返回左端点早的 bool cmp2(operation a,operation b) { return a.l<b.l; } //返回右端点早的 bool cmp3(operation a,operation b) { return a.r<b.r; } //快速输出一个整数 inline void pt(int x) { if (x<0) { putchar('-'); x=-x; } if(x>9)pt(x/10); putchar(x%10+'0'); } //快速读入一个整数 inline bool rd(int &ret) { char c; int sgn; if (c = getchar(), c == EOF) return 0; while (c != '-' && (c<'0' || c>'9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return 1; } int main() { //太多了,用到了再说吧 int n,oper,p,cnt,le,ri,ansl,ansr,curl,curr,cas=1,i,ll,rr,cs,id; while(~scanf("%d",&n)) { //cs计一共多少次加操作 cs=0; printf("Case #%d:\n",cas++); memset(rgt,0,sizeof(int)*(n+1)); memset(lft,0,sizeof(int)*(n+1)); //le,ri用来离散化 le=1; ri=1; cnt=1; //初始值设为-1,树状数组下标不能从0开始,否则会死循环 curl=-1; curr=-1; for(i=1;i<=n;i++) { rd(info[i].typ); rd(info[i].val); //标记第几次操作 info[i].id=i; //加操作 if(info[i].typ==0) { //左右区间赋值 info[i].l=info[i].val; info[i].r=info[i].l+cnt++; tmpstore[cs].l=info[i].l; tmpstore[cs].r=info[i].r; tmpstore[cs].id=info[i].id; cs++; //记录是第几次加操作 tmpstore[cs].times=cs; } } //先对l排序,离散化 sort(tmpstore,tmpstore+cs,cmp2); for(i=0;i<cs;i++) { ll=tmpstore[i].l; if(curl!=ll) { curl=ll; tmpstore[i].l=++le; } else tmpstore[i].l=le; } //再对r排序,r离散化 sort(tmpstore,tmpstore+cs,cmp3); for(i=0;i<cs;i++) { rr=tmpstore[i].r; if(curr!=rr) { curr=rr; tmpstore[i].r=++ri; } else tmpstore[i].r=ri; } //再将离散化后的结果更新回去 for(i=0;i<cs;i++) { id=tmpstore[i].id; info[id].l=tmpstore[i].l; info[id].r=tmpstore[i].r; } //按加的次序来 sort(tmpstore,tmpstore+cs,cmp1); for(i=1;i<=n;i++) { if(info[i].typ==0) { ll=info[i].l; rr=info[i].r; //左开右闭 ansl=get_sum1(ll-1); update1(ll,1); ansr=get_sum2(rr); update2(rr,1); pt(ansr-ansl); putchar('\n'); } else { //里面代表是第几次加操作,刚好和有序的tmpstore对应 update1(info[tmpstore[info[i].val-1].id].l,-1); update2(info[tmpstore[info[i].val-1].id].r,-1); } } } return 0; }