HDU5654(多种解法小结)
2016-03-31 00:33
211 查看
前言
题目不难,但是以前写这类题目总是感觉有点麻烦,现在来稍微小结一下。分析
离散化以后就变成了一个经典题。经典问题:区间[l,r][l,r]中共有多少个不同的数。
这道题比较常见的写法:离线线段树
当然主席树,莫队都可以写。
离线线段树
类似最长上升子序列的想法,从左向右更新,每个数在线段树中,只存放在最右边的位置,即每遇到一个数,先删除这个数的前一个位置,然后在现在的位置添加。这样就可以保证每一个数在线段树中只出现一次了。此时问题就变简单了: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_back const 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; }
主席树
写主席树就是无脑题了,不过这道题我的写法一直过不了,总是提示MLEMLE,好尴尬。#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 second typedef 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 second const 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; }
相关文章推荐
- git 下载源码到本地
- JavaScript之自我总结篇
- Masonry scrollview循环布局
- Qt浅谈之四十七下拉列表菜单
- Xcode快捷键
- c++笔记(3.30)
- 创业的第一百五十六天
- Masonry tableviewCell布局
- 3.27PSP及体会
- 设计模式学习笔记——命令模式
- spring(1)
- Masonry 比例(multipliedBy)
- 【8】JAVA---地址App小软件(AddrDaoFile .class)(数据层)
- 【8】JAVA---地址App小软件(AddrDaoFile .class)(数据层)
- Masonry自动布局:复合约束
- 随机生成题目的代码分析
- 睡觉前请关灯的 破解尝试版本 由已知解求一个矩阵的步骤
- Masonry整体动画更新约束
- 课本学习笔记4:第三章 20135115臧文君
- 作业2016