1. 程式人生 > >[POI2014]KUR-Couriers 洛谷p3567

[POI2014]KUR-Couriers 洛谷p3567

題目描述

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優化
}