1. 程式人生 > >bzoj5003: 與鏈 5004: 開鎖魔法II 5005:乒乓遊戲

bzoj5003: 與鏈 5004: 開鎖魔法II 5005:乒乓遊戲

one 實現 code iter 情況 style inf log 魔法

www.lydsy.com/JudgeOnline/upload/task.pdf

第一題題意可以轉為選一個長度k的序列,每一項二進制的1的位置被下一項包含,且總和為1,考慮每個二進制位的出現位置,可以轉化為一個多重背包求方案數的問題。

第二題構成一些環,可以每個環直接計算,然後合並答案。

第三題區間包含相當於單向邊,區間相交不包含就是雙向邊,將區間相交不包含的情況縮點,剩余的單向邊構成一棵樹(幾個被縮起來的區間可以用它們的並集表示),用lct維護樹形態,查詢即為詢問兩點是否是祖先關系,對於修改,由於區間長度遞增,只有至多兩種縮點情況:1.新加入的區間與某棵樹的根縮點(另用平衡樹維護所有根對應的區間,實際上需要再分幾類);2.新加入的區間與樹上非根的點縮點(另用線段樹維護所有非根節點對應的區間)。

前兩題代碼實現比較簡單,所以這裏只給出第三題的代碼。

技術分享
#include<bits/stdc++.h>
int _(){
    int x=0,f=1,c=getchar();
    while(c<48)c==-?f=-1:0,c=getchar();
    while(c>47)x=x*10+c-48,c=getchar();
    return x*f;
}
#define lc ch][0
#define rc ch][1
#define fa ch][2
const int N=2e5+77,inf=0x3f3f3f3f;
struct
itv{ int l,r,id; bool operator<(const itv&w)const{return l<w.l;} }; struct cmpl{bool operator()(const itv&a,const itv&b){return a.l>b.l;}}; struct cmpr{bool operator()(const itv&a,const itv&b){return a.r<b.r;}}; std::set<itv>st; int n,f[N],ch[N][4
],idp=0; int qs[N][3],xs[N],xp=0,mx=1,tl[577777],tr[577777]; std::priority_queue<itv,std::vector<itv>,cmpl>ls[N]; std::priority_queue<itv,std::vector<itv>,cmpr>rs[N]; int gf(int x){ while(x!=x[f])x=x[f]=x[f][f]; return x; } bool nrt(int x){return x==x[fa][lc]||x==x[fa][rc];} int wc(int x){return x==x[fa][rc];} void rot(int x){ int f=x[fa],g=f[fa],d=wc(x); if(nrt(f))g[ch][wc(f)]=x; x[fa]=g; (f[ch][d]=x[ch][d^1])[fa]=f; (x[ch][d^1]=f)[fa]=x; } void sp(int x){ while(nrt(x)){ int f=x[fa]; if(nrt(f))rot(wc(x)==wc(f)?f:x); rot(x); } } int acs(int x){int y=0;for(;x;sp(x),x[rc]=y,y=x,x=x[fa]);return y;} void lk(int a,int b){acs(a)[fa]=b;} void ctlk(int a,int b){acs(a),sp(a);a[lc][fa]=0,a[lc]=0,a[fa]=b;} int max(int a,int b){return a>b?a:b;} int min(int a,int b){return a<b?a:b;} void tl_up(int x){ tl[x+mx]=ls[x].size()?ls[x].top().l:inf; for(x=x+mx>>1;x;x>>=1)tl[x]=min(tl[x<<1],tl[(x<<1)+1]); } void tr_up(int x){ tr[x+mx]=rs[x].size()?rs[x].top().r:-inf; for(x=x+mx>>1;x;x>>=1)tr[x]=max(tr[x<<1],tr[(x<<1)+1]); } int $(int x){ return std::lower_bound(xs+1,xs+xp+1,x)-xs; } void tr_ins(itv w){ int _l=$(w.l),_r=$(w.r); ls[_r].push(w),tl_up(_r); rs[_l].push(w),tr_up(_l); } void chk(itv w,int z){ int p,u; while(tl[z]<w.l){ for(p=z;p<mx;p<<=1,p+=tl[p]>=w.l); p-=mx; u=ls[p].top().id; if(u==f[u])ctlk(u,f[u]=w.id); ls[p].pop(); tl_up(p); } while(tr[z]>w.r){ for(p=z;p<mx;p<<=1,p+=tr[p]<=w.r); p-=mx; u=rs[p].top().id; if(u==f[u])ctlk(u,f[u]=w.id); rs[p].pop(); tr_up(p); } } void tr_del(itv w){ for(int l=$(w.l)+mx,r=$(w.r)+mx;r-l>1;l>>=1,r>>=1){ if(~l&1)chk(w,l+1); if(r&1)chk(w,r-1); } } void ins(itv w){ tr_del(w); std::set<itv>::iterator it=st.lower_bound(w); if(it!=st.end()&&it->l==w.l&&it->r>w.r)return lk(w.id,f[w.id]=it->id); if(it!=st.begin()&&(--it)->r>w.l){ int u=it->id; if(it->r>=w.r)return lk(w.id,f[w.id]=u); w.l=it->l,f[u]=w.id; lk(u,w.id); st.erase(it); } while((it=st.lower_bound(w))!=st.end()&&it->l<w.r){ int u=it->id; if(it->r>w.r)w.r=it->r,f[u]=w.id; else tr_ins(*it); lk(u,w.id); st.erase(it); } st.insert(w); } bool query(int x,int y){ x=gf(x),y=gf(y); if(x==y)return 1; x=acs(x); int y0=y; for(;nrt(y);y=y[fa]); sp(y0); return x==y; } int main(){ n=_(); for(int i=1;i<=n;++i){ qs[i][0]=_(); qs[i][1]=_(); qs[i][2]=_(); if(qs[i][0]==1)xs[++xp]=qs[i][1],xs[++xp]=qs[i][2]; } std::sort(xs+1,xs+xp+1); for(;mx<=xp+5;mx<<=1); for(int i=mx*2-1;i;--i)tl[i]=inf,tr[i]=-inf; for(int i=1;i<=n;++i){ f[i]=i; int o=qs[i][0],x=qs[i][1],y=qs[i][2]; if(o==1)ins((itv){x,y,++idp}); else puts(query(x,y)?"YES":"NO"); } return 0; }
View Code

bzoj5003: 與鏈 5004: 開鎖魔法II 5005:乒乓遊戲