HDU5654(多种解法小结)
来源:互联网 发布:淘宝网男士保暖上衣 编辑:程序博客网 时间:2024/06/07 15:33
前言
题目不难,但是以前写这类题目总是感觉有点麻烦,现在来稍微小结一下。
分析
离散化以后就变成了一个经典题。
经典问题:区间
这道题比较常见的写法:离线线段树
当然主席树,莫队都可以写。
离线线段树
类似最长上升子序列的想法,从左向右更新,每个数在线段树中,只存放在最右边的位置,即每遇到一个数,先删除这个数的前一个位置,然后在现在的位置添加。这样就可以保证每一个数在线段树中只出现一次了。此时问题就变简单了:
1. 预处理前驱
2. 线段树的查询更新(树状数组)
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef vector <int> VI;typedef pair <int,int> PII;typedef pair <pair<int,int>,int> PIII;#define FOR(i,x,y) for(int i = x;i < y;++ i)#define IFOR(i,x,y) for(int i = x;i > y;-- i)#define fi first#define se second#define mp make_pair#define pb push_backconst int maxn = 200010;int n,q,c[maxn];int lowbit(int x) {return x&(-x);}void update(int x,int val){ while(x <= n){ c[x] += val; x += lowbit(x); }}int query(int x){ int ans = 0; while(x){ ans += c[x]; x -= lowbit(x); } return ans;}int sz,a[maxn],p[maxn],pl[maxn],ans[maxn];PIII b[maxn],cmd[maxn];void work(){ FOR(i,0,n) c[i] = 0; FOR(i,1,sz+1) pl[i] = -1; int cur = 1; FOR(i,0,q){ if(cmd[i].fi.fi < cmd[i].fi.se) {ans[cmd[i].se] = 0;continue;} for(;cur <= cmd[i].fi.fi;cur ++){ if(!p[cur]) continue; if(pl[p[cur]] != -1){ update(pl[p[cur]],-1); } update(cur,1); pl[p[cur]] = cur; } //printf("%d %d\n",query(cmd[i].fi.se-1),query(cmd[i].fi.fi)); ans[cmd[i].se] = query(cmd[i].fi.fi)-query(cmd[i].fi.se-1); } FOR(i,0,q) printf("%d\n",ans[i]);}int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); FOR(i,0,n) scanf("%d",&a[i]); sz = 0; FOR(i,1,n-1) if(a[i-1] <= a[i] && a[i] <= a[i+1]){ b[sz++] = mp(mp(a[i-1],a[i]),a[i+1]); } sort(b,b+sz); sz = unique(b,b+sz)-b; FOR(i,1,n-1){ if(a[i-1] <= a[i] && a[i] <= a[i+1]){ p[i] = lower_bound(b,b+sz,mp(mp(a[i-1],a[i]),a[i+1]))-b+1; } else p[i] = 0; } scanf("%d",&q); int l,r; FOR(i,0,q) {scanf("%d%d",&l,&r);cmd[i] = mp(mp(r-2,l),i);} sort(cmd,cmd+q); //FOR(i,0,q) printf("%d %d %d\n",cmd[i].fi.fi,cmd[i].fi.se,cmd[i].se); work(); } return 0;}
主席树
写主席树就是无脑题了,不过这道题我的写法一直过不了,总是提示
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef vector <int> VI;typedef pair <int,int> PII;#define FOR(i,x,y) for(int i = x;i < y;++ i)#define IFOR(i,x,y) for(int i = x;i > y;-- i)#define pb push_back#define mp make_pair#define fi first#define se secondtypedef pair <PII,int> PIII;const int maxn = 200010;int a[maxn],c[maxn],n,q,sz;vector <PIII > b;map <PIII,int> mat;void input(){ scanf("%d",&n); b.clear(); FOR(i,0,n) scanf("%d",&a[i]); FOR(i,2,n){ if(a[i-2] <= a[i-1] && a[i-1] <= a[i]){ b.pb(mp(mp(a[i-2],a[i-1]),a[i])); } } sort(b.begin(),b.end()); b.erase(unique(b.begin(),b.end()),b.end()); sz = b.size(); FOR(i,0,sz) mat[b[i]] = (i+1); FOR(i,2,n){ if(a[i-2] <= a[i-1] && a[i-1] <= a[i]){ c[i-1] = mat[mp(mp(a[i-2],a[i-1]),a[i])]; } else c[i-1] = 0; }}int rt[maxn],tot;struct Tree{ int ls,rs,sum;}tree[maxn*20];int build(int l,int r){ int o = tot++; tree[o].sum = 0; if(l == r) return o; int mid = (l+r)>>1; tree[o].ls = build(l,mid); tree[o].rs = build(mid+1,r); return o;}int update(int x,int l,int r,int lt,int val){ int o = tot++; tree[o] = tree[lt]; tree[o].sum += val; if(l == r) return o; int mid = (l+r)>>1; if(x <= mid) tree[o].ls = update(x,l,mid,tree[lt].ls,val); else tree[o].rs = update(x,mid+1,r,tree[lt].rs,val); return o;}void debug(int o,int l,int r){ if(l == r) {printf("%d:%d ",l,tree[o].sum);return;} int mid = (l+r)>>1; debug(tree[o].ls,l,mid); debug(tree[o].rs,mid+1,r);}void work(){ tot = 0; rt[0] = build(1,sz); FOR(i,2,n){ if(c[i-1]) rt[i-1] = update(c[i-1],1,sz,rt[i-2],1); else rt[i-1] = update(sz,1,sz,rt[i-2],0); } scanf("%d",&q); FOR(i,0,q){ int l,r; scanf("%d%d",&l,&r); r -= 2; if(r < l) printf("0\n"); else printf("%d\n",tree[rt[r]].sum - tree[rt[l-1]].sum); }}int main(){ int T; scanf("%d",&T); while(T--){ input(); work(); } return 0;}
莫队
感觉这道题在莫队上面也是比较经典的题。暴力添加,删除的时候如何维护最终答案。这个时候需要当前数的前驱和后驱,如果左边添加(删除)的话,看看这个数的后驱有没有超过当前区间(或者没有),如果右边添加(删除)的话,看看这个数的前驱有没有超过当前区间(或者没有)。
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef vector <int> VI;typedef pair <pair<int,int>,int> PIII;#define FOR(i,x,y) for(int i = x;i < y;++ i)#define IFOR(i,x,y) for(int i = x;i > y;-- i)#define mp make_pair#define pb push_back#define fi first#define se secondconst int maxn = 200200;const int M = (int)sqrt(maxn*1.0)+1;int a[maxn],c[maxn],n,q,sz;int pl[maxn],pr[maxn],p[maxn];int ans[maxn];PIII b[maxn];struct Commend{ int id,l,r; Commend() {} Commend(int x,int y,int z) : id(x),l(y),r(z) {} bool operator < (const Commend &rhs) const{ if(l/M == rhs.l/M) return r < rhs.r; return l/M < rhs.l/M; }}cmd[maxn];void input(){ scanf("%d",&n); FOR(i,0,n) scanf("%d",&a[i]); sz = 0; FOR(i,1,n-1){ if(a[i-1] <= a[i] && a[i] <= a[i+1]){ b[sz++] = mp(mp(a[i-1],a[i]),a[i+1]); } } sort(b,b+sz); sz = unique(b,b+sz)-b; FOR(i,1,n-1) pl[i] = pr[i] = -1; FOR(i,1,sz+1) p[i] = -1; FOR(i,1,n-1){ if(a[i-1] <= a[i] && a[i] <= a[i+1]){ PIII tem = mp(mp(a[i-1],a[i]),a[i+1]); int id = lower_bound(b,b+sz,tem)-b+1; pl[i] = p[id]; if(p[id] != -1) pr[p[id]] = i; p[id] = i; c[i] = id; } else c[i] = 0; } scanf("%d",&q); FOR(i,0,q){ int l,r; scanf("%d%d",&l,&r); r -= 2; cmd[i] = Commend(i,l,r); } sort(cmd,cmd+q);}void work(){ int L = 1,R = 0; int res = 0; FOR(i,0,q){ if(cmd[i].r < cmd[i].l) {ans[cmd[i].id] = 0;continue;} while(R < cmd[i].r){ R ++; if(c[R] && (pl[R] == -1 || pl[R] < L)) res ++; } while(R > cmd[i].r){ if(c[R] && (pl[R] == -1 || pl[R] < L)) res --; R --; } while(L < cmd[i].l){ if(c[L] && (pr[L] == -1 || pr[L] > R)) res --; L ++; } while(L > cmd[i].l){ L --; if(c[L] && (pr[L] == -1 || pr[L] > R)) res ++; } ans[cmd[i].id] = res; } FOR(i,0,q){ printf("%d\n",ans[i]); }}int main(){ //freopen("test.in","r",stdin); int T; scanf("%d",&T); while(T--){ input(); work(); } return 0;}
0 0
- HDU5654(多种解法小结)
- hduoj1874畅通工程续(多种解法)
- HDU 2544 最短路(多种解法)
- 字符串逆序(多种解法)
- 字符串逆序(多种解法)
- 求最长回文子串(多种解法)
- 【BZOJ】1293 [SCOI2009]生日礼物 (这题有多种解法)
- 【BZOJ】3314 [Usaco2013 Nov]Crowded Cows (多种解法)
- HDU 6096 String AC自动机(多种解法)
- 洗牌问题(多种解法以高效解法)
- POJ 1797 的多种解法
- 268. Missing Number多种解法
- S(n)=1+(1+2)+(1+2+3)+...(1+2+3+...n)多种解法
- poj 1077 & hdu 1043 Eight ( 多种解法:预处理、bfs、dbfs、IDA*、A*)
- 算法——Fibonacci数列的多种解法(递归算法)
- 连续自然数之和问题(多种解法)
- 一个数据库面试题的多种解法
- 0-1背包问题(多种解法)
- uva 10911Forming Quiz Teams
- 【8】JAVA---地址App小软件(AddrDaoFile .class)(数据层)
- javascript中的call,apply,callee,caller等的分析
- Xcode快捷键
- 169. Majority Element | Java最短代码实现
- HDU5654(多种解法小结)
- git 下载源码到本地
- CentOS引发的MySQL问题
- win7下nodejs的安装部署及helloworld实现
- Nginx学习笔记
- 1004. 成绩排名
- UICollectionView自定义布局——制作小相册
- 注册登录流程逻辑以及cookie的总结
- PHP 调用python 脚本实现python功能