zoukankan      html  css  js  c++  java
  • [BZOJ3642][CEOI 2014] Cake 线段树

    题意:

    Leopold买了n块蛋糕, 这些蛋糕排成一排,从左到右记为1到n,第i块蛋糕最初的美味度为di。
    Leopold每次固定最先吃第k块蛋糕,于是位置k就空出来了。之后他吃的每一块蛋糕总是位于某个空的位置旁边,并且是美味度最低的一块。因此在任何时刻,所有空的位置是一段连续的区间。Leopold会装饰自己的蛋糕来增加它的美味度,被加过装饰的蛋糕一定会成为最美味的10个蛋糕之一,任何时候都不存在两块美味度相同的蛋糕。
    Leopold想知道在他吃到某块蛋糕b之前需要吃掉多少块蛋糕。

    输入:

    第一行两个整数n和k,表示蛋糕的数量和Leopold吃的第一块蛋糕的位置。
    第二行n个不同的整数d1,d2...,dn,表示第i块蛋糕最初的美味度。
    第三行一个整数q,表示操作的数量。
    下面q行会包括以下两种操作。
    (1)E i e 蛋糕i被装饰成了第e美味的蛋糕(即原来前e-1美味的蛋糕不变,原来第e美味的蛋糕变成了第e+1美味的蛋糕,以此类推)注意每次装饰一定会增加美味度。
    (2)F b输出Leopold吃到蛋糕b之前需要吃掉多少块蛋糕。

    输出:

    对于每个F操作,输出一行一个整数,表示蛋糕的数量。

    样例略

    思路:

    先考了不带修改的情况:

    先按照最初的美味值进行编号,放到一棵线段树(当然根据K分成两边放到两个线段树上也可以)。

    假设我们需要查询的(x)(k)的左端,我们可以先查询([x,k-1])这段区间内排名的最小值(Mi),分析能吃掉这个排名最小(即美味值最高的蛋糕)的情况是在(k)的右边存在的一个蛋糕排名更小或者是右边不存在蛋糕了,因此我们要找到右边区间内,第一个小于当前(Mi)的位置。

    (不带修改的当然可以一次直接用数组处理所有的蛋糕第几个吃掉,但这对后面的写法没有任何帮助)

    接下来考虑修改:

    当我们将(x)的排名变成(e)时,我们可以直接将(x)的排名变成当前第一的排名-1(因为这里是按照排名越小美味值越高算的),对于([1,e-1])区间内的蛋糕,将它们的排名再依次进行减1

    因为(e)的范围是在([1,10])之内的,所以我们只用记录前十的蛋糕是哪一些。

    更新排名的时候有一个注意点:

    如果(x)的原来排名是(7),变成了(3),那么需要进行移动的排名是([3,6])而不是([3,10]),所以要特别判一下(x)的排名是不是已经在前十当中;

    #include<bits/stdc++.h>
    #define M 250005
    using namespace std;
    int n,K,q,Rank[M],Id[M];
    struct node {
    	int id,x;
    	bool operator<(const node&_)const {
    		return x>_.x;
    	}
    } a[M];
    struct Tree {
    	struct Node {
    		int mi;
    	} tree[M<<2];
    	void up(int p) {
    		tree[p].mi=min(tree[p<<1].mi,tree[p<<1|1].mi);
    	}
    	void updata(int L,int R,int x,int v,int p) {
    		if(L==R) {
    			tree[p].mi=v;
    			return;
    		}
    		int mid=(L+R)>>1;
    		if(x<=mid)updata(L,mid,x,v,p<<1);
    		else updata(mid+1,R,x,v,p<<1|1);
    		up(p);
    	}
    	void build(int l,int r,int p) {
    		if(l==r) {
    			tree[p].mi=Id[l];
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(l,mid,p<<1),build(mid+1,r,p<<1|1);
    		up(p);
    	}
    	int Query(int L,int R,int l,int r,int p) {
    		if(L==l&&R==r)return tree[p].mi;
    		int mid=(L+R)>>1;
    		if(r<=mid)return Query(L,mid,l,r,p<<1);
    		else if(l>mid)return Query(mid+1,R,l,r,p<<1|1);
    		else return min(Query(L,mid,l,mid,p<<1),Query(mid+1,R,mid+1,r,p<<1|1));
    	}
    	int find_l(int L,int R,int x,int p) { //需要吃的在右边 ,从左边找
    		if(tree[p].mi>x)return L-1;
    		if(L==R)return L;
    		int mid=(L+R)>>1;
    		if(tree[p<<1|1].mi<x)return find_l(mid+1,R,x,p<<1|1);
    		else return find_l(L,mid,x,p<<1);
    	}
    	int find_r(int L,int R,int x,int p) {
    		if(tree[p].mi>x)return R+1;
    		if(L==R)return L;
    		int mid=(L+R)>>1;
    		if(tree[p<<1].mi<x)return find_r(L,mid,x,p<<1);
    		else return find_r(mid+1,R,x,p<<1|1);
    	}
    
    } Tl,Tr;
    char s[2];
    int main() {
    	int now=1;//用来记录当前最小的排名
    	scanf("%d%d",&n,&K);
    	for(int i=1; i<=n; i++)scanf("%d",&a[i].x),a[i].id=i;
    	sort(a+1,a+n+1);
    	int tot=0;
    	for(int i=1; i<=n; i++)Rank[i]=a[i].id,Id[a[i].id]=i;//记录最初的排名
    	if(K!=1)Tl.build(1,K-1,1);
    	if(K!=n)Tr.build(K+1,n,1);
    	scanf("%d",&q);
    	while(q--) {
    		scanf("%s",s);
    		if(s[0]=='F') {
    			int x;
    			scanf("%d",&x);
    			if(x==K)printf("0
    ");
    			else if(x>K) {
    				int k=Tr.Query(K+1,n,K+1,x,1),l=0;
    				if(K!=1)l=K-1-Tl.find_l(1,K-1,k,1);
    				printf("%d
    ",l+x-K);
    			} else {
    				int k=Tl.Query(1,K-1,x,K-1,1),r=0;
    				if(K!=n)r=Tr.find_r(K+1,n,k,1)-K-1;
    				printf("%d
    ",r+K-x);
    			}
    		} else {
    			int x,y,p=min(n,10);
    			scanf("%d%d",&x,&y);
    			for(int i=1; i<=min(n,10); i++)if(Rank[i]==x)p=i;//判断x原来的位置是不是在前十
    			for(int i=p-1; i>=y; i--)Rank[i+1]=Rank[i];//更新前十的排名
    			Rank[y]=x;
    			for(int i=y; i>=1; i--) {
    				now--;
    				if(Rank[i]>K)Tr.updata(K+1,n,Rank[i],now,1);
    				else if(Rank[i]<K)Tl.updata(1,K-1,Rank[i],now,1);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    求最大公约数伪代码
    XOR加密
    20201225张晓平第五周学习
    pep9课下作业 张晓平
    20201225 张晓平《信息安全专业导论》第四周学习总结
    寻找黑客偶像 20201225张晓平
    《信息安全专业导论》第九周学习总结
    《信息安全专业导论》第八周学习总结
    《信息安全专业导论》第七周学习总结
    《信息安全专业导论》第6周学习总结
  • 原文地址:https://www.cnblogs.com/cly1231/p/11213110.html
Copyright © 2011-2022 走看看