离线专题学习
来源:互联网 发布:成本数据分析 编辑:程序博客网 时间:2024/05/22 18:22
hdu 4288
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4288
这题是往一个升序的集合里面加数字或者是减数字,然后求集合里面的一个值
#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define MAX 100005#define MAXN 500005#define maxnode 105#define sigma_size 2#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define lrt rt<<1#define rrt rt<<1|1#define middle int m=(r+l)>>1#define LL long long#define ull unsigned long long#define mem(x,v) memset(x,v,sizeof(x))#define lowbit(x) (x&-x)#define pii pair<int,int>#define bits(a) __builtin_popcount(a)#define mk make_pair#define limit 10000//const int prime = 999983;const int INF = 0x3f3f3f3f;const LL INFF = 0x3f3f;const double pi = acos(-1.0);const double inf = 1e18;const double eps = 1e-9;const LL mod = 1e9+7;const ull mx = 1333333331;/*****************************************************/inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';}/*****************************************************/char op[MAX][10];int a[MAX];int b[MAX];LL sum[MAX<<2][5];int num[MAX<<2];void build(int l,int r,int rt){ num[rt]=0; for(int i=0;i<5;i++) sum[rt][i]=0; if(l==r) return; middle; build(lson); build(rson);}void pushup(int rt){ for(int i=0;i<5;i++) sum[rt][i]=sum[lrt][i]+sum[rrt][5-((num[lrt]-i-1)%5+5)%5-1];}void update(int l,int r,int rt,int pos,int d,int v){ num[rt]+=v; if(l==r){ sum[rt][0]+=d; return; } middle; if(pos<=m) update(lson,pos,d,v); else update(rson,pos,d,v); pushup(rt);}int main(){ //freopen("test.txt","r",stdin); int n; while(~scanf("%d",&n)){ int tmp=0; for(int i=0;i<n;i++){ scanf("%s",op[i]); if(op[i][0]!='s'){ scanf("%d",&a[i]); b[tmp++]=a[i]; } } build(1,n,1); sort(b,b+tmp); int tot=unique(b,b+tmp)-b; for(int i=0;i<n;i++){ int pos=lower_bound(b,b+tot,a[i])-b+1; if(op[i][0]=='a') update(1,n,1,pos,a[i],1); else if(op[i][0]=='d') update(1,n,1,pos,-a[i],-1); else printf("%I64d\n",sum[1][2]); } } return 0;}
hdu 4417
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4417
这题问你区间里比H小的数字有多少个,也是离线搞辣,因为H很大,首先要离散化,之后就是把区间按照区间的高度从小到大排序,然后把符合的放进线段树里面,然后区间查询就可以了辣
代码:
#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#define MAX 100005#define MAXN 500005#define maxnode 105#define sigma_size 2#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define lrt rt<<1#define rrt rt<<1|1#define middle int m=(r+l)>>1#define LL long long#define ull unsigned long long#define mem(x,v) memset(x,v,sizeof(x))#define lowbit(x) (x&-x)#define pii pair<int,int>#define bits(a) __builtin_popcount(a)#define mk make_pair#define limit 10000//const int prime = 999983;const int INF = 0x3f3f3f3f;const LL INFF = 0x3f3f;const double pi = acos(-1.0);const double inf = 1e18;const double eps = 1e-9;const LL mod = 1e9+7;const ull mx = 1333333331;/*****************************************************/inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';}/*****************************************************/struct num{ int a,pos; bool operator < (const num &b) const{ return a<b.a; }}pp[MAX];struct Node{ int l,r,h,id,ans;}p[MAX];bool cmp1(Node a,Node b){ return a.h<b.h;}bool cmp2(Node a,Node b){ return a.id<b.id;}int sum[MAX<<2];void build(int l,int r,int rt){ sum[rt]=0; if(l==r) return ; middle; build(lson); build(rson);}void pushup(int rt){ sum[rt]=sum[lrt]+sum[rrt];}void update(int l,int r,int rt,int pos){ if(l==r){ sum[rt]++; return; } middle; if(pos<=m) update(lson,pos); else update(rson,pos); pushup(rt);}int query(int l,int r,int rt,int L,int R){ if(L<=l&&r<=R) return sum[rt]; middle; int ans=0; if(L<=m) ans+=query(lson, L,R); if(R>m) ans+=query(rson,L,R); return ans;}int main(){ //freopen("test.txt","r",stdin); int t,kase=0; cin>>t; while(t--){ int n,m; cin>>n>>m; for(int i=0;i<n;i++){ int a; scanf("%d",&a); pp[i]=(num){a,i+1}; } sort(pp,pp+n); for(int i=0;i<m;i++){ int l,r,h; scanf("%d%d%d",&l,&r,&h); p[i]=(Node){l+1,r+1,h,i,0}; } sort(p,p+m,cmp1); int ret=0; build(1,n,1); for(int i=0;i<m;i++){ while(pp[ret].a<=p[i].h&&ret<n){ update(1,n,1,pp[ret].pos); ret++; } p[i].ans=query(1,n,1,p[i].l,p[i].r); } sort(p,p+m,cmp2); kase++; printf("Case %d:\n",kase); for(int i=0;i<m;i++) printf("%d\n",p[i].ans); } return 0;}
hdu 3874
http://acm.hdu.edu.cn/showproblem.php?pid=3874
题意:求解区间内不重复数字的和
题解:这题莫队随手秒杀,但是要好好用离线线段树的方法解决,让我想了挺久,首先我们要处理出来每个位置的数字,往前最近的一个和它相同的数字在哪个位置,然后区间按照右端点排序,然后先把所有数字都插进线段树,如果此时在i,那就删除pre[i]位置的这个数字,然后在i位置插入这个数字。
查询的时候右端点从右往左扫过来,假设此时在i位置,已经超出这个区间右端点,则在pre[i]的位置加上这个值,然后区间查询(保证此时i不在这个区间内)
代码:
#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;#define MAX 50005#define MAXN 6005#define maxnode 15#define sigma_size 30#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define lrt rt<<1#define rrt rt<<1|1#define middle int m=(r+l)>>1#define LL long long#define ull unsigned long long#define mem(x,v) memset(x,v,sizeof(x))#define lowbit(x) (x&-x)#define pii pair<int,int>#define bits(a) __builtin_popcount(a)#define mk make_pair#define limit 10000//const int prime = 999983;const int INF = 0x3f3f3f3f;const LL INFF = 0x3f3f;const double pi = acos(-1.0);//const double inf = 1e18;const double eps = 1e-8;const LL mod = 1e9+7;const ull mx = 133333331;/*****************************************************/inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/struct Node{ int l,r,id; bool operator < (const Node&e)const{ return r>e.r; }}p[MAX*4];LL ans[MAX*4];int a[MAX];int pos[1000005];int pre[MAX];LL sum[MAX<<2];void pushup(int rt){ sum[rt]=sum[lrt]+sum[rrt];}void build(int l,int r,int rt){ sum[rt]=0; if(l==r) return; middle; build(lson); build(rson); pushup(rt);}void update(int l,int r,int rt,int pos,int d){ if(l==r){ sum[rt]=d; return; } middle; if(pos<=m) update(lson,pos,d); else update(rson,pos,d); pushup(rt);}LL query(int l,int r,int rt,int L,int R){ if(L<=l&&r<=R) return sum[rt]; middle; LL ans=0; if(L<=m) ans+=query(lson,L,R); if(R>m) ans+=query(rson,L,R); return ans;}int main(){ int t; cin>>t; while(t--){ int n; cin>>n; mem(pre,-1); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); pos[a[i]]=-1; } for(int i=1;i<=n;i++){ if(pos[a[i]]!=-1){ pre[i]=pos[a[i]]; pos[a[i]]=i; } else pos[a[i]]=i; } build(1,n,1); int m; cin>>m; for(int i=0;i<m;i++){ int l,r; scanf("%d%d",&l,&r); p[i]=(Node){l,r,i}; } sort(p,p+m); for(int i=1;i<=n;i++){ if(pre[i]!=-1) update(1,n,1,pre[i],0); update(1,n,1,i,a[i]); } int r=n; for(int i=0;i<m;i++){ while(r>p[i].r){ if(pre[r]!=-1) update(1,n,1,pre[r],a[r]); r--; } ans[p[i].id]=query(1,n,1,p[i].l,p[i].r); } for(int i=0;i<m;i++){ printf("%I64d\n",ans[i]); } } return 0;}
hdu 4638
http://acm.hdu.edu.cn/showproblem.php?pid=4638
题意:求一个区间内,连续数字段的个数,比如一个区间内有1 2 3 4 5 ,就是一段,有1 2 4 ,就是两段。
这题也是莫队即可瞬秒,但是线段树的方法也是很难想,从莫队的维护的方法上考虑过来,如果一个数字出现,就把它当作独立的一段,就是个这个位置+1,然后如果和它相邻的数字出现,就应该-1,但是这个-1应该减哪里,如果我们枚举每个位置,然后看区间右端点是否小于这个位置来查询的话,如果相邻的两个数字都不在区间里,而这个位置-1的话,就会错误,所以应该是在相邻的数字的位置处-1.
考虑 1 2 3 ,扫到1,1位置+1,扫到2,2位置+1,1位置-1,然后查询是一段,扫到3, 3位置+1,2位置-1,查询[1,3]是1,查询[2,3]也是1,而此时不能查询[1,2],[1,2]这个区间应该是在扫到2的时候就查询了。
所以我们的方法是区间按照右端点排序,然后碰到一个点,就把他自己的位置+1,然后如果他的+1和-1的数字也在这个点的左边,那就在它们的位置上-1,然后碰到这个区间的时候就查询一下。
代码:
#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;#define MAX 100005#define MAXN 6005#define maxnode 15#define sigma_size 30#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define lrt rt<<1#define rrt rt<<1|1#define middle int m=(r+l)>>1#define LL long long#define ull unsigned long long#define mem(x,v) memset(x,v,sizeof(x))#define lowbit(x) (x&-x)#define pii pair<int,int>#define bits(a) __builtin_popcount(a)#define mk make_pair#define limit 10000//const int prime = 999983;const int INF = 0x3f3f3f3f;const LL INFF = 0x3f3f;const double pi = acos(-1.0);//const double inf = 1e18;const double eps = 1e-8;const LL mod = 1e9+7;const ull mx = 133333331;/*****************************************************/inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/int pos[MAX];int a[MAX];struct que{ int l,r,id; bool operator < (const que&e)const{ return r<e.r; }}p[MAX];int ans[MAX];int sum[MAX<<2];void pushup(int rt){ sum[rt]=sum[lrt]+sum[rrt];}void build(int l,int r,int rt){ if(l==r){ sum[rt]=0; return; } middle; build(lson); build(rson); pushup(rt);}void update(int l,int r,int rt,int pos,int d){ if(l==r){ sum[rt]+=d; return; } middle; if(pos<=m) update(lson,pos,d); else update(rson,pos,d); pushup(rt);}int query(int l,int r,int rt,int L,int R){ if(L<=l&&r<=R) return sum[rt]; middle; int ans=0; if(L<=m) ans+=query(lson,L,R); if(R>m) ans+=query(rson,L,R); return ans;}int main(){ int t; cin>>t; while(t--){ int n,m; cin>>n>>m; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); pos[a[i]]=i; } for(int i=0;i<m;i++){ int l,r; scanf("%d%d",&l,&r); p[i]=(que){l,r,i}; } sort(p,p+m); build(1,n,1); int tot=0; for(int i=1;i<=n;i++){ update(1,n,1,i,1); if(pos[a[i]-1]&&pos[a[i]-1]<=i) update(1,n,1,pos[a[i]-1],-1); if(pos[a[i]+1]&&pos[a[i]+1]<=i) update(1,n,1,pos[a[i]+1],-1); while(tot<m&&p[tot].r==i){ ans[p[tot].id]=query(1,n,1,p[tot].l,p[tot].r); tot++; } } for(int i=0;i<m;i++) printf("%d\n",ans[i]); } return 0;}
- 离线专题学习
- 线段树离线处理专题
- tarjan 离线求 lca (专题)
- 离线LCA学习
- 在线学习与离线学习
- SQl语句学习专题
- JavaBean学习专题
- PLSQL学习 数组专题
- linux学习专题
- 计算几何专题学习
- [专题学习][计算几何]
- JAVA多线程学习专题
- Windbg 专题学习
- [树链剖分]专题,学习记录
- java学习的专题
- dfs序专题学习
- UML的学习专题
- 树链剖分学习专题
- 通过HttpURLConnection模拟post表单提交
- ubuntu下100%成功安装torch,同时配置cuda和cudnn(不成功,则成仁)
- Mvc模版页制作
- 浏览器滚动条的兼容性问题
- B+树 习题解
- 离线专题学习
- VC 绘图映射模式之间的转换关系示意
- 矩阵翻转
- Verilog中阻塞赋值和非阻塞赋值区别
- freeswitch新增app接口
- 逻辑回归
- 想搞个nas (1)
- 新手入门git: 使用git管理自己的代码
- ORA-30078: partition bound must be TIME/TIMESTAMP WITH TIME ZONE literals