題解 P3765 【總統選舉】
阿新 • • 發佈:2020-09-02
原文連結
很有意思的一道題。
Part.1
一開始拿到這道題一看,題目要求的是區間眾數的出現次數,這個顯然沒法做,據我所知只有靜態分塊或者回滾莫隊可以做不帶修版本的,但是他要我們求的比這個要弱許多,我們可以發現一個性質,顯然如果一個數出現次數超過一半,我們讓它與剩下的數兩兩抵消,剩下的數必然只有它自己。更進一步,如果區間中一旦有一個滿足條件的數,我們任意選不同的兩個數抵消,剩下的必然是那個數。
我們用資料結構實現這個過程。
考慮一棵線段樹,她維護區間中兩兩抵消還剩哪個數以及還剩多少。她的左右兒子資訊合併時,我們看兩個兒子剩下的數是否一樣,如果一樣就相加,如果不一樣就取最大,然後互相抵消。
Part.2
然後,你以為做完了?
如果真做完了那麼它最多是綠題。
我們剛才假設了區間絕對滿足條件,那麼如果區間不滿足條件呢?暴力找
一個顯然的做法是對每一個總統建一個\(vector\),每次找出答案後再\(vector\)中二分詢問區間的左右端點,然後看中間數的個數是否大於\(len/2\)就可以了。
然而題目中有修改。暴力修改
於是實際上,我們要支援一個數據結構,插入一個數,刪除一個數,查詢某個數的排名(相當與二分)
這是什麼?平衡樹板子。
然後,然後就真的完了。
總結一下,我們每次線上段樹上找出一個數,然後再在平衡樹上找出區間中該數的個數檢查是否合法就可以了。
Part.3
安利一下\(LeafyTree\)
最後一個細節,在找排名的時候,一路走到葉子後一定要看一下這個數是不是比葉子大,如果小要\(return\;0\),因為這個數可能比平衡樹中的所有數都小。
Code
struct Node { int siz,val; Node *lc,*rc; Node(int siz,int val,Node *lc,Node *rc) : siz(siz),val(val),lc(lc),rc(rc) {} Node() {} }*null,*stk[maxn*3],utk[maxn*3]; int utot,a[maxn],n; struct Leafy_Tree { Node *rt[maxn]; #define newnode(a,b,c,d) (&(*stk[utot++]=Node(a,b,c,d))) #define merge(a,b) newnode(a->siz+b->siz,b->val,a,b) inline void init() { for(int i=1;i<=n;++i) rt[i]=newnode(1,0x3f3f3f3f,null,null); } inline void rotate(Node *u) { if(u->lc->siz > u->rc->siz*ratio) u->rc=merge(u->lc->rc,u->rc),stk[--utot]=u->lc,u->lc=u->lc->lc; else if(u->rc->siz > u->lc->siz*ratio) u->lc=merge(u->lc,u->rc->lc),stk[--utot]=u->rc,u->rc=u->rc->rc; } inline void pushup(Node *u) { if(!u->lc->siz) return; u->siz=u->lc->siz+u->rc->siz; u->val=u->rc->val; } inline void insert(Node *u,int val) { if(u->siz==1) { u->lc=newnode(1,min(u->val,val),null,null); u->rc=newnode(1,max(u->val,val),null,null); } else insert(val > u->lc->val?u->rc:u->lc,val); pushup(u);rotate(u); } inline void erase(Node *u,int val) { if(u->lc->siz==1&&u->lc->val==val) stk[--utot]=u->lc,stk[--utot]=u->rc,*u=*u->rc; else if(u->rc->siz==1&&u->rc->val==val) stk[--utot]=u->lc,stk[--utot]=u->rc,*u=*u->lc; else erase(val > u->lc->val?u->rc:u->lc,val); pushup(u);rotate(u); } inline int rnk(Node *u,int val) { if(u->siz==1) return val>=u->val; return val > u->lc->val ? rnk(u->rc,val)+u->lc->siz : rnk(u->lc,val); } }leafy; struct Segment_Tree { int mx[maxn],cnt[maxn]; inline void pushup(int u) { if(mx[u<<1]==mx[u<<1|1]) mx[u]=mx[u<<1],cnt[u]=cnt[u<<1]+cnt[u<<1|1]; else if(cnt[u<<1]>cnt[u<<1|1]) mx[u]=mx[u<<1],cnt[u]=cnt[u<<1]-cnt[u<<1|1]; else mx[u]=mx[u<<1|1],cnt[u]=cnt[u<<1|1]-cnt[u<<1]; } inline void build(int u,int l,int r) { if(l==r) {mx[u]=a[l],cnt[u]=1;return;} int mid=(l+r)>>1; build(u<<1,l,mid);build(u<<1|1,mid+1,r); pushup(u); } inline void modify(int u,int l,int r,int x,int val) { if(l==r) {mx[u]=val;return;} int mid=(l+r)>>1; if(x<=mid) modify(u<<1,l,mid,x,val); else modify(u<<1|1,mid+1,r,x,val); pushup(u); } inline pii query(int u,int l,int r,int x,int y) { if(x<=l&&r<=y) return make_pair(mx[u],cnt[u]); int mid=(l+r)>>1; if(y<=mid) return query(u<<1,l,mid,x,y); else if(x>mid) return query(u<<1|1,mid+1,r,x,y); else { pii a=query(u<<1,l,mid,x,y),b=query(u<<1|1,mid+1,r,x,y),c; if(a.first==b.first) c.first=a.first,c.second=a.second+b.second; else if(a.second>b.second) c.first=a.first,c.second=a.second-b.second; else c.first=b.first,c.second=b.second-a.second; return c; } } }seg; inline void modify(int x,int val) { leafy.erase(leafy.rt[a[x]],x); leafy.insert(leafy.rt[val],x); seg.modify(1,1,n,x,val); a[x]=val; } inline int query(int x,int y) { int ans=seg.query(1,1,n,x,y).first; if(((y-x+1)>>1)<leafy.rnk(leafy.rt[ans],y)-leafy.rnk(leafy.rt[ans],x-1)) return ans; else return -1; } template<typename T> inline void read(T &x) { char c;int f=1; while(!isdigit(c=getchar())) (c=='-')&&(f=-1); x=c^48; while(isdigit(c=getchar())) x=x*10+(c^48); x*=f; } int main() { int l,r,s,k,m,x; for(int i=0;i<maxn*3;++i) stk[i]=&utk[i]; null=new Node(0,0,0,0); read(n);read(m); for(int i=1;i<=n;++i) read(a[i]); leafy.init(); seg.build(1,1,n); for(int i=1;i<=n;++i) leafy.insert(leafy.rt[a[i]],i); while(m--) { read(l);read(r);read(s);read(k); x=query(l,r); if(x!=-1) s=x; printf("%d\n",s); while(k--) read(x),modify(x,s); } printf("%d\n",query(1,n)); return 0; }