URAL 2080 Wallet 莫队算法

2080. Wallet

Time limit: 2.0 second
Memory limit: 256 MB
Eugene is not a student struggling to pay his bills anymore. Now he lives in a big city and works for a well-known IT-company. He forgot the times when his wallet contained only his father’s credit card with no money on it; now it’s full with Eugene’s own various credit, discount and membership cards.
Every week Eugene follows the same routine: he visits the same places in the same order and talks with the same people. There is no place for surprises and complications in his life. Finally, after several months in a strange city, he can just perform a pre-determined order of actions and not trouble himself with anything.
However, Eugene does have one problem: sometimes in a store, restaurant or even at a subway station entrance he has to search his wallet for the right card for more than 5 seconds. Eugene hates to waste his precious time on that.
Cards in Eugene’s wallet are stored as a stack. Ha wants to be able to just take the top one every time he needs to pay or get a discount for something. After using a card he has no problem with inserting it in any position of the stack.
Knowing an order in which cards are going to be used throughout the week one can easily find a way to assemble them so that the top one will always be the right card to use. Eugene could have done that himself, but he doesn’t feel like solving this problem. You do it.

Input

The first line of the input contains two integers  n and  k (1 ≤  nk ≤ 10 5) — total number of cards Eugene has in his wallet and the number of times he uses them during the week. The cards are enumerated with integer numbers from 1 to  n.
The second line contains  k numbers  a 1a 2, …,  a k (1 ≤  a i ≤  n), separated by spaces: cards’ numbers in the order they are to be used.

Output

Output  k+1 lines.
The first line should contain  n card numbers separated by spaces from 1 to  n — the initial order of cards in the stack, from top to bottom.
The line number ( i + 1) should contain one number — how many cards will be located higher in the stack than the card  a i after it has been used and returned into the wallet.
If there are several correct solutions, output any of them.

Sample

input output
3 5
3 1 2 2 1
3 1 2 
2
1
0
1
0


给一列数,先输出出现顺序,再求相邻的相同数值的数之间有多少个不同的数值。


莫队算法在离线查询方面果然是无敌的!


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <bitset>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
const int maxn=100005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f; 
const ld pi=3.1415926535898L;
int a[maxn],ans[maxn],pre[maxn],t[maxn];

struct query{
	int l,r,kuai;
};
query q[maxn];

bool cmp(query a,query b) {
	return a.kuai<b.kuai || (a.kuai==b.kuai&&a.r<b.r);
}

int main() {
	int n,k,i,j,flag=0,m=0;
	scanf("%d%d",&n,&k);
	mem0(pre);
	int size=sqrt(n);
	for (i=1;i<=k;i++) {
		scanf("%d",&a[i]);
		if (!pre[a[i]]) {
			printf("%d ",a[i]);
		} else {
			q[++m].l=pre[a[i]];q[m].r=i-1;q[m].kuai=pre[a[i]]/size;
		}
		pre[a[i]]=i;
	}
	for (i=1;i<=n;i++) {
		if (!pre[i]) printf("%d ",i);
	}
	printf("\n");
	sort(q+1,q+m+1,cmp);
	mem0(t);
	memset(ans,-1,sizeof(ans));
	int b=0,nl,nr;
	for (i=q[1].l;i<=q[1].r;i++) {
		if (!t[a[i]]) b++;
		t[a[i]]++;
	}
	ans[q[1].l]=b-1;
	nl=q[1].l;nr=q[1].r;
	for (i=2;i<=m;i++) {
//		cout << q[i].l << ' ' << q[i].r << endl;
		while (nl<q[i].l) {
			t[a[nl]]--;
			if (t[a[nl]]==0) b--;
			nl++;
		}
		while (nl>q[i].l) {
			if (t[a[nl-1]]==0) b++;
			t[a[nl-1]]++;
			nl--;
		}
		while (nr>q[i].r) {
			t[a[nr]]--;
			if (t[a[nr]]==0) b--;
			nr--;
		}
		while (nr<q[i].r) {
			if (t[a[nr+1]]==0) b++;
			t[a[nr+1]]++;
			nr++;
		}
		ans[q[i].l]=b-1;
	} 
	for (i=1;i<=k;i++) {
		if (ans[i]==-1) printf("%d\n",n-1); 
		    else printf("%d\n",ans[i]);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值