jzoj 2902 集訓隊互測2012 middle(陳立傑)
【題解】
這題雖然不是這幾天做的,但是最近在搞資料結構,再總結一下還是會有收穫的。
(複習時應該看看)
設乙個序列s從大到小排序後為s[1..k],則中位數為m=s[k/2向上取整]。
那就意味著,在序列s中,大於等於m的數大於等於k/2。如果把序列s轉化為t,t[i]=1(s[i]>=m),-1(s[i]
這樣我們很容易想到乙個演算法:二分答案+主席樹
1.先按位置建一棵葉子節點權值為1的原始線段樹(第乙個版本的線段樹)。要維護區間和sum,區間左側最大字首和lsum,和右側最大字首和rsum。
2.然後按權值從小到大的順序依次在相應的位置修改,每次新建乙個版本的線段樹(可持久化)
假設當前到第i個版本的線段樹,則要把第i-1大的數的位置權值修改為-1。這樣在第i個版本的線段樹上,比第i大的數還大(或等於)的數的位置上值為1,否則為-1。
3.二分答案。
二分到k時,就在第k個版本的線段樹上查詢。(程式實現時root[0]為第乙個版本線段樹的根)。
若query(root[k-1],1,n,ask[1],ask[2]).rsum + query(root[k-1],1,n,ask[2]+1,ask[3]-1).sum + query(root[k-1],1,n,ask[3],ask[4]).lsum >= 0,就說明k可以為中位數,繼續二分。
#include#include#include#include#include#define fo(i,a,b) for (int i = a;i <= b;i ++)
#define fd(i,a,b) for (int i = a;i >= b;i --)
using namespace std;
const int maxn = 2000000;
struct node
node(int a,int b,int c)
};int root[maxn];
node tree[maxn];
int a[maxn],b[maxn],pos[maxn];
int n,q,tot,n,last;
int ask[10];
bool cmp(int x,int y)
void readin()
void discretize()
void update(int z)
void addpoint(int &z,int x,int l,int r,int p)
else
else
update(z); }}
void filltree(int &z,int l,int r)
else }
void maketree()
void initialize()
node query(int z,int l,int r,int x,int y)
}bool check(int k)
void work()
last = a[pos[l]];
printf("%d\n",a[pos[l]]);
}int main(void)
return 0;
}
集訓隊互測 2012 Attack
description chnlich非常喜歡玩三國志這款遊戲,並喜歡用一些策略出奇制勝。現在,他要開始征服世界的旅途了。他的敵人有n nn座城市和n nn個太守,n nn個城市可以看作在二維平面上的n nn個點。n nn座城市的標號為0,1 2,n 1 0,1,2,cdots,n 1 0,1,2,...
2019集訓隊互測 學習軌跡(貪心)
首先沒有限制的話排個序就完事了。如果有限制的話,顯然我們需要幹的事情就是做出修正。按照權值從小到大排序。考慮什麼情況下非法,權值小的依賴權值大的。這個時候的修正非常明顯,把這個區間拎出來,無依賴的公升序,然後有依賴的降序排在後面。這樣的區間可以通過一次差分字首和找出來。容易注意到有的時候我們把若干個...
集訓隊互測2015 Robot
題目描述 題解 維護兩顆線段樹,維護最大值和最小值,因為每次只有單點查詢,所以可以直接在區間插入線段就可以了。注意卡常,不要寫stl,用鍊錶把同類修改串起來就好了。pragma gcc optimize 2 pragma gcc optimize 3 include include include ...