BZOJ 4399 魔法少女LJJ
阿新 • • 發佈:2018-12-22
行合並 pro else 分析 str 表示 復雜 for upd 棵線段樹後復雜度就是消失的點的個數,不會超過總共的點數,所以復雜度是 \(n \log n\) 的。
題意
https://www.lydsy.com/JudgeOnline/problem.php?id=4399
思路
碼農題,需要一定代碼功底。方法很暴力,先將權值離散,表示在線段樹裏儲存的位置,每個連通塊用一棵動點線段樹存儲,合並兩個連通塊直接對兩個動點線段樹進行合並,查詢操作在當前連通塊的線段樹上進行,只不過有詢問乘積大小,直接權值取原權值的 \(\ln?\) ,比較和的大小即可。
現在分析線段樹合並的復雜度,舉一個最基本的例子:權值為\([1,n]\) ,\(n\) 棵動點線段樹,每個線段樹插入了一個權值,那麽總共有 \(n\log n\) 個點,而每一次合並相當於少掉了一個點,那麽合並完這 \(n\)
類似的,對最一般的情況,也是一樣的分析方法,最後得出線段樹合並的復雜度為節點個數的結論。
代碼
#include<bits/stdc++.h> #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i) #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i) typedef long long LL; using namespace std; const int N=4e5+5; const int NN=N*12; struct SegmentTree { struct node { int cnt;double sum; node operator +(const node &_)const { return (node){cnt+_.cnt,sum+_.sum}; } }; node nd[NN]; int lson[NN],rson[NN],rt[N],tot; int &operator [](const int x){return rt[x];} void build() { memset(rt,0,sizeof(rt)); nd[tot=0]=(node){0,0}; lson[0]=rson[0]=0; } void create(int &k) { if(!k)k=++tot,nd[k]=nd[0],lson[k]=rson[k]=0; } void update(int &k,int x,int addcnt,double addsum,int l,int r) { create(k); if(l==r) { nd[k].cnt+=addcnt; nd[k].sum+=addsum; return; } int mid=(l+r)>>1; if(x<=mid)update(lson[k],x,addcnt,addsum,l,mid); else update(rson[k],x,addcnt,addsum,mid+1,r); nd[k]=nd[lson[k]]+nd[rson[k]]; } int sweep_off(int &k,int L,int R,int l,int r) { if(!k)return 0; if(L<=l&&r<=R){int res=nd[k].cnt;k=0;return res;} int mid=(l+r)>>1,res=0; if(L<=mid)res+=sweep_off(lson[k],L,R,l,mid); if(R>mid)res+=sweep_off(rson[k],L,R,mid+1,r); nd[k]=nd[lson[k]]+nd[rson[k]]; return res; } int querycnt(int k){return nd[k].cnt;} double querysum(int k){return nd[k].sum;} int queryKth(int k,int K,int l,int r) { if(l==r)return l; int mid=(l+r)>>1; if(nd[lson[k]].cnt>=K)return queryKth(lson[k],K,l,mid); else return queryKth(rson[k],K-nd[lson[k]].cnt,mid+1,r); } void merge(int &x,int y,int l,int r) { if(!x||!y){x=(x|y);return;} if(l==r){nd[x]=nd[x]+nd[y];return;} int mid=(l+r)>>1; merge(lson[x],lson[y],l,mid); merge(rson[x],rson[y],mid+1,r); nd[x]=nd[lson[x]]+nd[rson[x]]; } }ST; int n,m,fa[N]; int op[N],a[N],b[N]; int disc[N],tot; double logdisc[N]; int getfa(int k){return k==fa[k]?k:fa[k]=getfa(fa[k]);} int main() { scanf("%d",&m); FOR(i,1,m) { scanf("%d%d",&op[i],&a[i]); if(op[i]!=1&&op[i]!=7)scanf("%d",&b[i]); } FOR(i,1,m) { if(op[i]==1)disc[++tot]=a[i]; else if(op[i]==3||op[i]==4)disc[++tot]=b[i]; } sort(disc+1,disc+1+tot); tot=unique(disc+1,disc+1+tot)-disc-1; FOR(i,1,m) { if(op[i]==1)a[i]=lower_bound(disc+1,disc+1+tot,a[i])-disc; else if(op[i]==3||op[i]==4)b[i]=lower_bound(disc+1,disc+1+tot,b[i])-disc; } FOR(i,1,tot)logdisc[i]=log(disc[i]); ST.build(); FOR(i,1,m) { if(op[i]==1) { n++; fa[n]=n; ST.update(ST[n],a[i],1,logdisc[a[i]],1,tot); } else if(op[i]==2) { a[i]=getfa(a[i]),b[i]=getfa(b[i]); if(a[i]==b[i])continue; ST.merge(ST[a[i]],ST[b[i]],1,tot); fa[b[i]]=a[i]; } else if(op[i]==3) { if(b[i]==1)continue; a[i]=getfa(a[i]); int cnt=ST.sweep_off(ST[a[i]],1,b[i]-1,1,tot); ST.update(ST[a[i]],b[i],cnt,cnt*logdisc[b[i]],1,tot); } else if(op[i]==4) { if(b[i]==tot)continue; a[i]=getfa(a[i]); int cnt=ST.sweep_off(ST[a[i]],b[i]+1,tot,1,tot); ST.update(ST[a[i]],b[i],cnt,cnt*logdisc[b[i]],1,tot); } else if(op[i]==5) { a[i]=getfa(a[i]); printf("%d\n",disc[ST.queryKth(ST[a[i]],b[i],1,tot)]); } else if(op[i]==6) { a[i]=getfa(a[i]),b[i]=getfa(b[i]); if(ST.querysum(ST[a[i]])>ST.querysum(ST[b[i]])) puts("1"); else puts("0"); } else if(op[i]==7) { a[i]=getfa(a[i]); printf("%d\n",ST.querycnt(ST[a[i]])); } } return 0; }
BZOJ 4399 魔法少女LJJ