【题目描述】
lemon最近迷上了优秀考智商的卡牌游戏(垃圾氪金)——游戏王。最为集换式卡牌鼻祖级的游戏,游戏王伴随了许多人的一生。在k社无节操地维护环境下,游戏王充满了无穷的可能性。但是lemon不知道如何组卡组(游戏王卡片出得太多了!lemon记不完),所以他找来了你来帮忙。现在他只想选一些怪兽卡作为自己的魂卡(们),(lemon:我又不是主角可以印卡逆天,攻防当然越高越好啦!!!)
有如下规则:
1.卡池有t张怪兽牌。
2.lemon需要q次查询,给你一个flag,
当flag=1时,每次查询区间[l,r]上攻击力最大的牌的攻击力a,
当flag=0时,每次查询区间[l,r]上防御力最大的牌的防御力d。
【输入格式】
输入第一行有两个整数t,q分别表示卡池中卡牌总数,与查询次数。
接下来t行,每行三个整数Ci,Ai,Di,分别表示卡片种类,卡片攻击力,卡片防御力。
接下来q行,每行三个整数fi,li,ri,f如题目描述中所述,表示查询类型,l,r表示查询区间,数据保证r>l,f只为1与0。
【输出格式】
输出共q行,每行一个整数,表示所询问的答案。
【样例输入】
6 2
1 4 9
1 4 9
2 3 4
3 4 5
4 5 20
5 30 5
1 2 3
0 1 5
【样例输出】
9
20
【提示】
对于30%的数据t≤100000,q≤100000
对于60%的数据t≤100000,q≤1000000
对于100%的数据t≤1000000,q≤1000000
所有数据均为非负整数,且都不大于2147483647。
数据保证合法,一道水题。
TANKS FOR YOUR VIEW
【来源】
lemonoil
就是一个RMQ,两种做法,
第一种是
O(n)
的RMQ,效率不错
#include <cstdio>
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;
void read(int &x) {
char c;bool flag = 0;
while((c=getchar())<'0'||c>'9') flag |= (c=='-');
x=c-'0';while((c=getchar())>='0'&&c<='9') x = (x<<3)+(x<<1)+c-'0';
flag?x=-x:x;
}
#define N 1410000
int ans[N];
struct RMQ {
struct Node {
int val,key,l,r;
Node(int val = 0,int key = 0):val(val),key(key),l(-1),r(-1){}
}t[N<<1];
int S[N],top,pos[N],sz;
void dfs(int o) {
if(o == -1) return;
dfs(t[o].l);
pos[t[o].key] = o;
dfs(t[o].r);
}
void build(int a[],int n) {
t[0] = Node(2147483647,n+1);
S[top = 1] = 0; sz = 0;
for (int i = 1; i <= n; i++) {
t[++sz] = Node(a[i],i);
int p = -1;
while(t[S[top]].val <= t[sz].val) p = S[top--];
t[sz].l = p; t[S[top]].r = sz;
S[++top] = sz;
}
dfs(0);
}
struct Que {int y,id;};
int f[N],v[N],Lca[N];
vector<Que> q[N];
int fd(int x) {
return x==f[x] ? x : f[x]=fd(f[x]);
}
void Tarjan(int x) {
v[x] = 1; f[x] = x;
for (int i = 0; i < 2; i++) {
int to = i?t[x].l:t[x].r;
if(to != -1 && !v[to]) {
Tarjan(to);
f[to] = x;
}
}
for (int i = 0; i < q[x].size(); i++)
if(v[q[x][i].y] && !Lca[q[x][i].id])
Lca[q[x][i].id] = fd(q[x][i].y);
}
void slove (int m,int L[],int R[],int Cas[],int c) {
for (int i = 1; i <= m; i++) {
if(Cas[i] != c) continue;
int l = pos[L[i]],r = pos[R[i]];
q[l].push_back((Que){r,i});
q[r].push_back((Que){l,i});
}
Tarjan(0);
for (int i = 1; i <= m; i++)
if(Lca[i]) ans[i] = t[Lca[i]].val;
}
}tx,ty;
int n,m,a[N],x[N],y[N],l[N],r[N],cas[N];
int main() {
freopen("ygocrad.in","r",stdin);freopen("ygocrad.out","w",stdout);
read(n); read(m);
for (int i = 1,useless; i <= n; i++) read(useless),read(x[i]),read(y[i]);
tx.build(x,n); ty.build(y,n);
for (int i = 1; i <= m; i++) read(cas[i]),read(l[i]),read(r[i]);
tx.slove(m,l,r,cas,1);
ty.slove(m,l,r,cas,0);
for (int i = 1; i <= m; i++) printf("%d\n",ans[i]);
return 0;
}
其实这道题更多的是考高位寻址优化,详见洛可强大大的论文。
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
const int MAX = 1000005;
const int LOGMAX = 26;
int n,q,tot;
int st_maxf[LOGMAX][MAX],st_maxs[LOGMAX][MAX];
void make_st(){
register int i, j, k;
for(j=1;(1<<j)<=n;j++){
k=1<<(j-1);
for(i=0;i+k<n;i++){
st_maxf[j][i]=max(st_maxf[j-1][i],st_maxf[j-1][i+k]),
st_maxs[j][i]=max(st_maxs[j-1][i],st_maxs[j-1][i+k]);
}
}
}
int rmq(int a, int b, int flag){
int dis=abs(b-a)+1;
register int k;
for(k=0;(1<<k)<=dis;++k);k--;
if(flag){
return max(st_maxf[k][a],st_maxf[k][b-(1<<k)+1]);
}else{
return max(st_maxs[k][a],st_maxs[k][b-(1<<k)+1]);
}
}
inline void read(int &res){
static char ch;
while((ch=getchar())<'0'||ch>'9');res=ch-48;
while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;
}
int main(){
//freopen("rmq.in","r",stdin);
//freopen("rmq.out","w",stdout);
freopen( "ygocrad.in", "r", stdin );
freopen( "ygocrad.out", "w", stdout );
read(n),read(q);
register int i,x;
for(i = 0; i<n; i++){
read(x),read(st_maxf[0][i]),read(st_maxs[0][i]);
}
make_st();
for(i=0;i<q;i++){
int a,b,f;
read(f),read(a),read(b);
printf("%d\n",rmq(a-1,b-1,f));
}
return 0;
}
用上高位寻址优化的 O(nlogn2) 的RMQ竟然比 O(n) 的RMQ快,不想说话,下次用内存卡死你。。。。。。