[POI2014]KUR-Couriers 洛谷p3567

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MrTinTin/article/details/83342287

题目描述

Byteasar works for the BAJ company, which sells computer games.

The BAJ company cooperates with many courier companies that deliver the games sold by the BAJ company to its customers.

Byteasar is inspecting the cooperation of the BAJ company with the couriers.

He has a log of successive packages with the courier company that made the delivery specified for each package.

He wants to make sure that no courier company had an unfair advantage over the others.

If a given courier company delivered more than half of all packages sent in some period of time, we say that it dominated in that period.

Byteasar wants to find out which courier companies dominated in certain periods of time, if any.

Help Byteasar out!

Write a program that determines a dominating courier company or that there was none.

给一个数列,每次询问一个区间内有没有一个数出现次数超过一半

输入输出格式

输入格式:

The first line of the standard input contains two integers,  and  (), separated by a single space, that are the number of packages shipped by the BAJ company and the number of time periods for which the dominating courier is to be determined, respectively.

The courier companies are numbered from  to (at most) .

The second line of input contains  integers,  (), separated by single spaces;  is the number of the courier company that delivered the -th package (in shipment chronology).

The  lines that follow specify the time period queries, one per line.

Each query is specified by two integers,  and  (), separated by a single space.

These mean that the courier company dominating in the period between the shipments of the -th and the -th package, including those, is to be determined.

In tests worth  of total score, the condition  holds, and in tests worth  of total score .

输出格式:

The answers to successive queries should be printed to the standard output, one per line.

(Thus a total of  lines should be printed.) Each line should hold a single integer: the number of the courier company that dominated in the corresponding time period, or  if there was no such company.

输入输出样例

输入样例#1: 复制

7 5
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6

输出样例#1: 复制

1
0
3
0
4

说明

给一个数列,每次询问一个区间内有没有一个数出现次数超过一半

这题可以这么考虑,我们直接把读入的数字插入到主席树中,

然后对于询问[i,j],

在[1..n]中我们看看小于mid的数字有多少个,显然如果个数的两倍<=j-i+1那么[1..mid]中就不存在,

不然我们再看看大于mid的数字有多少个,同理,

如果两个都不行,就返回0,递归搞一搞就好了。

#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=500005;
struct Node{
	int l,r,w;
}T[MAXN*30];
int n,m;
int root[MAXN],tot;
inline void change(int last,int &x,int l,int r,int pos,int d)
{
	x=++tot;
	T[x]=T[last];
	T[x].w+=d;
	if(l==r) return;
	int mid=l+r>>1;
	if(pos<=mid) change(T[last].l,T[x].l,l,mid,pos,d);
	else change(T[last].r,T[x].r,mid+1,r,pos,d);
}
inline int Kth(int i,int j,int l,int r,int k)
{
	if(l==r) return l;
	int mid=l+r>>1;
	if(2*(T[T[i].l].w-T[T[j].l].w)>k) return Kth(T[i].l,T[j].l,l,mid,k);
	if(2*(T[T[i].r].w-T[T[j].r].w)>k) return Kth(T[i].r,T[j].r,mid+1,r,k);
	return 0;
}
int main()
{
	//ios::sync_with_stdio(false);
	int i,j,x,l,r;
	cin>>n>>m;
	f(i,1,n){
		scanf("%d",&x);
		change(root[i-1],root[i],1,n,x,1);
	}
	f(i,1,m){
		scanf("%d%d",&l,&r);
		printf("%d\n",Kth(root[r],root[l-1],1,n,r-l+1));
	}
	return 0;
}

莫队算法。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=500007;
int a[N],n,m,size,Ans[N],num[N],flag,len;
const int ch_top=4e8+3;
char ch[ch_top],*now_r=ch-1,*now_w=ch-1;
inline int read(){
    while(*++now_r<'0');
    register int x=*now_r-'0';
    while(*++now_r>='0')x=x*10+*now_r-'0';
    return x;
}//读入优化
inline void write(ll x){
    static char st[20];static int top;
    while(st[++top]='0'+x%10,x/=10);
    while(*++now_w=st[top],--top);
    *++now_w='\n';
}//输出优化
struct node1{int tot,id;}b[N];//存储出现次数
struct node2{int l,r,pos,id;}c[N];//存储询问信息
inline bool cmp1(node1 a,node1 b){
    if(a.tot==b.tot)return a.id<b.id;
    return a.tot>b.tot;
}
inline bool cmp2(node2 a,node2 b){
    if(a.pos==b.pos)return b.pos&1?a.r<b.r:a.r>b.r;
    return a.l<b.l;
}//莫队的玄学优化
int main(){
    fread(ch,1,ch_top,stdin);
    n=read(),m=read();
    size=sqrt(n);
    for(register int i=1;i<=n;++i){
        a[i]=read();
        b[a[i]].tot++;//记录每个数在数列中出现次数
        b[a[i]].id=a[i];//记录数值方便调用
    }
    for(register int i=1;i<=m;++i){
        c[i].l=read();//区间左端点
        c[i].r=read();//区间右端点
        c[i].id=i;//询问编号
        c[i].pos=(c[i].l-1)/size+1;//莫队日常
    }
    sort(b+1,b+n+1,cmp1);
    sort(c+1,c+m+1,cmp2);
    int l=1,r=0,ans=0;
    for(register int i=1;i<=m;++i){
        len=(c[i].r-c[i].l+1)>>1,flag=0;
        while(l<c[i].l)num[a[l++]]--;//左指针出界,调整
        while(r>c[i].r)num[a[r--]]--;//右指针出界,调整
        while(l>c[i].l)if(++num[a[--l]]>len)flag=1,ans=a[l];//左指针在区间内的情况
        while(r<c[i].r)if(++num[a[++r]]>len)flag=1,ans=a[r];//右指针在区间内的情况
        //若在区间内且满足条件,特判
        if(!flag){
            for(register int j=1;b[j].tot>len;++j)//按总出现次数进行枚举
                if(num[b[j].id]>len){
                    flag=1;
                    ans=b[j].id;
                    break;//满足条件后退出
                }
        }
        if(flag)Ans[c[i].id]=ans;//记录答案
            else Ans[c[i].id]=0;
    }
    for(register int i=1;i<=m;i++)write(Ans[i]);
    fwrite(ch,1,now_w-ch,stdout);//IO优化
}

猜你喜欢

转载自blog.csdn.net/MrTinTin/article/details/83342287
今日推荐