1. 程式人生 > >bzoj P5016[Snoi2017]一個簡單的詢問——solution

bzoj P5016[Snoi2017]一個簡單的詢問——solution

第一行,一個數字N,表示序列長度。 第二行,N個數字,表示a1~aN 第三行,一個數字Q,表示詢問個數。 第4~Q+3行,每行四個數字l1,r1,l2,r2,表示詢問。 N,Q≤50000 N1≤ai≤N 1≤l1≤r1≤N 1≤l2≤r2≤N 注意:答案有可能超過int的最大值                          -by bzoj http://www.lydsy.com/JudgeOnline/problem.php?id=5016 一開始看錯了題,以為是每次詢問一個x, 然後想直接主席樹; 然後很快發現題不會這麼簡單; 詢問兩個區間對應顏色出現次數相乘再求和; 兩個區間,顏色; 想到離線 把一個有兩個區間的詢問變成兩個有一個區間和一個字首的詢問作差, 然後按字首端點排序,逐漸右移端點,維護更長的字首,以更新詢問, 這樣每次字首的端點右移時,字首裡只有一個顏色的數量增加了1, 相應的,以後要詢問的區間只有這個顏色對答案的貢獻增加了區間中這個顏色的個數, 然而這個顏色對答案的貢獻取決於詢問的區間中有多少這個顏色, 換言之取決於詢問哪個區間, 一開始想用什麼主席樹之類的維護,死活不會, 然後一看時限3S想到分塊暴力, 然後發現很科學; 然後就有了這個做法 把詢問(l1,r1,l2,r2)拆成(l1,r1,pos=l2-1,-),(l1,r1,pos=r2,+) 表示 詢問[l1,r1]與l2-1字首的結果,並在原詢問中減去它 詢問[l1,r1]與r2字首的結果,並在原詢問中加上它 將拆成來的詢問按pos從小到大排序, 按這樣的順序處理詢問可以通過單向右移端點來依次維護所有詢問的字首 查詢的時候,採用分塊, 被整塊查詢的塊可以直接使用一個塊在當前字首下的答案 維護方法是 在讀入數列時對每個塊建一個顏色桶MP[] 每右移字首端點,使顏色col(x)個數在字首中增加時,把每個塊的答案都增加MP[col(x)] 被查詢的散點,每個散點對答案的貢獻是當前字首中與這個散點顏色相同的點的個數 可以開個桶,在字首變長時逐漸更新即可, 複雜度為$O((N+M)\sqrt{N})$ 程式碼:
 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define LL long long
 6 using namespace std;
 7 int sz,N,Q,num;
 8 int a[50010];
 9 LL MAP[233][50010],inlineMAP[50010];
10 LL ANS[233];
11 struct ss{
12     int L,R,pos,id;
13     LL flag;
14 }qrr[100010]; 15 LL ans[50010]; 16 bool cmp(ss a,ss b){ 17 return a.pos<b.pos; 18 } 19 LL get(int ,int ); 20 int main() 21 { 22 int i,j,k; 23 scanf("%d",&N); 24 sz=sqrt(N); 25 for(i=num=1;i<=N;i+=sz,num++){ 26 for(j=i;j<i+sz&&j<=N;j++){ 27 scanf("
%d",&a[j]); 28 MAP[num][a[j]]++; 29 } 30 } 31 num--; 32 scanf("%d",&Q); 33 for(i=1;i<=Q;i++){ 34 scanf("%d%d%d%d",&qrr[i].L,&qrr[i].R,&qrr[i].pos,&qrr[i+Q].pos); 35 qrr[i+Q].L=qrr[i].L,qrr[i+Q].R=qrr[i].R; 36 qrr[i+Q].id=qrr[i].id=i;
37 qrr[i].flag=-1,qrr[i+Q].flag=1; 38 qrr[i].pos--; 39 } 40 sort(qrr+1,qrr+Q+Q+1,cmp); 41 j=0; 42 for(i=1;i<=Q<<1;i++){ 43 while(j<qrr[i].pos){ 44 j++; 45 inlineMAP[a[j]]++; 46 for(k=1;k<=num;k++) 47 ANS[k]+=MAP[k][a[j]]; 48 } 49 ans[qrr[i].id]+=qrr[i].flag*get(qrr[i].L,qrr[i].R); 50 } 51 for(i=1;i<=Q;i++) 52 printf("%lld\n",ans[i]); 53 return 0; 54 } 55 LL get(int L,int R){ 56 LL ret=0; 57 int i,j,k; 58 int l,r; 59 if(R-L+1<=sz){ 60 for(i=L;i<=R;i++) 61 ret+=inlineMAP[a[i]]; 62 return ret; 63 } 64 for(i=j=1;i<L;i+=sz,j++); 65 l=i-1; 66 for(;i+sz<=R+1&&i<=N;j++,i+=sz) 67 ret+=ANS[j]; 68 r=i; 69 for(i=L;i<=l;i++) 70 ret+=inlineMAP[a[i]]; 71 for(i=r;i<=R;i++) 72 ret+=inlineMAP[a[i]]; 73 return ret; 74 }

或許有樹套樹的做法?

相關推薦

bzoj P5016[Snoi2017]一個簡單詢問——solution

第一行,一個數字N,表示序列長度。 第二行,N個數字,表示a1~aN 第三行,一個數字Q,表示詢問個數。 第4~Q+3行,每行四個數字l1,r1,l2,r2,表示詢問。 N,Q≤50000 N1≤ai≤N 1≤l1≤r1≤N 1≤l2≤r2≤N 注意:答案有可能超過int的最大值  

【bzoj5016】[Snoi2017]一個簡單詢問 莫隊算法

bsp math 輸出 load 存在 不能 int 註意 sort 題目描述 給你一個長度為N的序列ai,1≤i≤N和q組詢問,每組詢問讀入l1,r1,l2,r2,需輸出 get(l,r,x)表示計算區間[l,r]中,數字x出現了多少次。 輸入 第

[Snoi2017]一個簡單詢問

oid etc 容易 char names 轉化 spa 但是 efi 數據範圍很容易讓人想到莫隊算法 但是對於每次詢問有\(l_1,r_1,l_2,r_2\)四個參數 很不方便維護 所以可以將詢問差分 \(get(l,r,x)=get(1,r,x)-get(1,l-1,x

BZOJ5016 Snoi2017一個簡單詢問(莫隊)

string 莫隊 ace cst truct print bsp for har   容易想到區間轉化成前綴和。這樣每個詢問有了二維坐標,莫隊即可。 #include<iostream> #include<cstdio> #include<

BZOJ5016:[SNOI2017]一個簡單詢問(莫隊)

gen mat unit src long cmp nod \n 公式 Description 給你一個長度為N的序列ai,1≤i≤N和q組詢問,每組詢問讀入l1,r1,l2,r2,需輸出 get(l,r,x)表示計算區間[l,r]中,數字x出現了多少次

BZOJ5016[Snoi2017]一個簡單詢問

sum tchar bound times struct bzoj zoj mes pac BZOJ5016[Snoi2017]一個簡單的詢問 題面:BZOJ 解析 這題的ider挺有意思的。看看數據範圍,多半是莫隊,但直接統計答案又不行(有4個參數啊),來拆式子,設\(Q

[BZOJ5016]一個簡單詢問

可能 註意 img 不等式 元組 個數字 超過 ios width 給你一個長度為N的序列ai,1≤i≤N和q組詢問,每組詢問讀入l1,r1,l2,r2,需輸出 get(l,r,x)表示計算區間[l,r]中,數字x出現了多少次。 Input 第一行,一個數字N,表示序列

寫了一個簡單輪播效果實現

char line query span size html ef6 ava top <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">

linux設備驅動第三篇:寫一個簡單的字符設備驅動

提示 copy flags 驅動程序 相關 clas open ugo param 在linux設備驅動第一篇:設備驅動程序簡介中簡單介紹了字符驅動,本篇簡單介紹如何寫一個簡單的字符設備驅動。本篇借鑒LDD中的源碼,實現一個與硬件設備無關的字符設備驅動,僅僅操

ionic 最簡單的路由形式,頭部固定,下面tab切換-------一個簡單的單頁切換起飛了

top log cnblogs .cn inset badge left plus set <ion-header-bar class="bar-dark" align-title="left"> <h1 class="title" >微信 &l

初遇C#:一個簡單的小程序(圓形周長,面積計算器)

編碼 雙精度 崩潰 輸入 面向對象 窗口 語句 readline 面向對象的語言 作為一個面向對象的語言,與用戶的交互很關鍵! 在此,我們可以先分析一下我們這個小程序要與用戶交互的內容:1.命名很重要,讓用戶看見這個程序就知道這個程序的作用。 2.當用戶打開這個程序時,提示

封裝一個簡單的UI組件

span query indent block 年份 函數 方法 his prev   方法其實很簡單,用一個函數把整個過程包起來。調用時用new,這樣可以在一個頁面使用多個改組件。這是一個非常簡單的方法,後面還有很大改進的空間。下面是一個封裝日歷的示例。   現在我們的

寫了一個簡單的Linux Shell用來下載文件

logs -- spi http col 內容 style bre shell #!/bin/sh for (( i=0; i<30; i=i+1 )); do # 利用spider來探測請求的資源是否存在,並把請求的結果寫入到一個文件 wget -

【Java編程】建立一個簡單的JDBC連接-Drivers, Connection, Statement and PreparedStatement

code ava 語句 ole man for out 讀取 drop 本blog提供了一個簡單的通過JDBC驅動建立JDBC連接例程,並分別通過Statement和PreparedStatement實現對數據庫的查詢。在下一篇blog中將重點比較Statement與P

一個簡單演示樣例來演示用PHP訪問表單變量

time 變量 value 購物車 size post方法 form sso val 首先編寫表單頁面orderform.html,用post方法請求服務端腳本文件:processorder.php orderform.html: <!DOCTYPE html&

采用jsp頁面與java代碼分離的方式寫一個簡單的二維表

color arraylist 一個 3-9 業務 動態顯示 復雜 分層架構 方式 前提:在我們做程序時追求的是高內聚,低耦合,但是如果我們把jsp頁面的的代碼和java的代碼都放在了jsp的代碼編寫中,使java和jsp高耦合這樣的話不僅使jsp代碼頁面顯得很復雜,而

自己打造了一個簡單的站長工具

spl logs images fan net ref 分享 style image 自己打造了一個簡單的站長工具   站長工具:www.fanguzai.net/ 自己打造了一個簡單的站長工具

一個簡單的時間片輪轉多道程序內核操作系統工作流程

gson star 高級 time author family num 個數 count 一.操作系統工作概述 存儲程序計算機工作模型,計算機系統最最基礎性的邏輯結構; 函數調用堆棧,高級語言得以執行的基礎; 中斷。多道程序操作系統的基點。 二.代

用Java GUI做一個簡單的管理系統

java 管理系統 gui 1.先完成主頁面MainUI(代碼如下)package com.pag_1; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.

slz-用eclipse制作一個簡單的程序

.cn src 建立 步驟 cli 制作 com logs .com 步驟 1:建立一個名為slz-用eclipse制作一個簡單的程序