[BZOJ 4399] 魔法少女LJJ
魔法少女LJJ
Description :
题目描述
在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了
LJJ感叹道“这里真是个迷人的绿色世界,空气清新、淡雅,到处散发着醉人的奶浆味;小猴在枝头悠来荡去,好不自在;各式各样的鲜花争相开放,各种树枝的枝头挂满沉甸甸的野果;鸟儿的歌声婉转动听,小河里飘着落下的花瓣真是人间仙境”
SHY觉得LJJ还是太naive,一天,SHY带着自己心爱的图找到LJJ,对LJJ说:“既然你已经见识过动态树,动态仙人掌了,那么今天就来见识一下动态图吧”
LJJ:“要支持什么操作?”
SHY:“
1.新建一个节点,权值为x。
2.连接两个节点。
3.将一个节点a所属于的联通快内权值小于x的所有节点权值变成x。
4.将一个节点a所属于的联通快内权值大于x的所有节点权值变成x。
5.询问一个节点a所属于的联通块内的第k小的权值是多少。
6.询问一个节点a所属联通快内所有节点权值之积与另一个节点b所属联通快内所有节点权值之积的大小。
7.询问a所在联通快内节点的数量
8.若两个节点a,b直接相连,将这条边断开。
9.若节点a存在,将这个点删去。
”
LJJ:“我可以离线吗?”
SHY:“可以,每次操作是不加密的,”
LJJ:“我可以暴力吗?”
SHY:“自重”
LJJ很郁闷,你能帮帮他吗
数据范围及提示:
Solution:
我们会发现后面两种恶心到令人发指的操作根本不用实现(
我们维护一些并查集以支持连边操作,然后每个并查集上开一颗权值线段树,每次连边就将两颗树合并。但是我们会发现乘积貌似有点难维护,但是题目只要求比大小,所以我们并不需要维护乘积的真实值,维护对数就好了。
然后修改操作就在
细节提示:
由于这题的删除标记是要 pushdown 的,所以我们在 merge 时一定要将 x,y 都 pushdown
然后就是不推荐使用太过先进的编译器。因为在并查集时,你的 find 函数就算没有 return ,编译器也可能帮你返回一个你最后调用的变量。例如:
int find(int x){fa[x] = fa[x]==x ? fa[x] : find(fa[x]);}
在我的编译器上是会直接返回 fa[x] 的,而不会报错。这两个致命错误导致我在本地调了 3h+
(╯°Д°)╯︵ ┻━┻
然后这题就做完了
Code:
#include<bits/stdc++.h> const int N=4e5+5; const int inf=1e9; using namespace std; int n,tot; struct Segment_Tree{ struct Tree{ int ls,rs,cnt,tag; double val; }t[N*40]; int cnt,rt[N]; void erase(int x){t[x].cnt=0,t[x].val=0,t[x].tag=1;} void pushdown(int x) { if(!t[x].tag)return; erase(t[x].ls),erase(t[x].rs); t[x].tag=0; } void pushup(int x){t[x].cnt=t[t[x].ls].cnt+t[t[x].rs].cnt;t[x].val=t[t[x].ls].val+t[t[x].rs].val;} int merge(int x,int y,int l,int r) { if(!x||!y)return x|y; if(l==r){t[x].cnt+=t[y].cnt,t[x].val+=t[y].val;return x;} int mid=l+r>>1; pushdown(x);pushdown(y); t[x].ls=merge(t[x].ls,t[y].ls,l,mid); t[x].rs=merge(t[x].rs,t[y].rs,mid+1,r); pushup(x); return x; } void insert(int &x,int l,int r,int pos,int k) { x=(x ? x : ++cnt); if(l==r){t[x].cnt+=k;t[x].val+=1.0*k*log(pos);return;} int mid=l+r>>1; pushdown(x); if(pos<=mid)insert(t[x].ls,l,mid,pos,k); if(mid<pos) insert(t[x].rs,mid+1,r,pos,k); pushup(x); } void upd(int x,int l,int r,int L,int R,int &res) { if(L<=l&&r<=R) { res+=t[x].cnt; erase(x); return; } int mid=l+r>>1; pushdown(x); if(L<=mid)upd(t[x].ls,l,mid,L,R,res); if(mid<R) upd(t[x].rs,mid+1,r,L,R,res); pushup(x); } int query(int x,int l,int r,int k) { pushdown(x); if(l==r)return l; int mid=l+r>>1; if(k<=t[t[x].ls].cnt)return query(t[x].ls,l,mid,k); else return query(t[x].rs,mid+1,r,k-t[t[x].ls].cnt); } }T; int fa[N]; int find(int x){return fa[x] = fa[x]==x ? fa[x] : find(fa[x]);} void work() { cin>>n; for(int i=1,opt,x,y;i<=n;i++) { scanf("%d%d",&opt,&x); if(1<opt&&opt<7)scanf("%d",&y); if(opt==1) { tot++; fa[tot]=tot; T.insert(T.rt[tot],1,inf,x,1); } if(opt==2) { int u=find(x),v=find(y); if(u!=v) { fa[v]=u; T.rt[u]=T.merge(T.rt[u],T.rt[v],1,inf); } } if(opt==3) { int tmp=0; x=find(x); T.upd(T.rt[x],1,inf,1,y-1,tmp); T.insert(T.rt[x],1,inf,y,tmp); } if(opt==4) { int tmp=0; x=find(x); T.upd(T.rt[x],1,inf,y+1,inf,tmp); T.insert(T.rt[x],1,inf,y,tmp); } if(opt==5) { x=find(x); int ans=T.query(T.rt[x],1,inf,y); printf("%d\n",ans); } if(opt==6) { x=find(x),y=find(y); printf("%d\n",(T.t[T.rt[x]].val > T.t[T.rt[y]].val ? 1 : 0)); } if(opt==7) { x=find(x); printf("%d\n",T.t[T.rt[x]].cnt); } } } int main() { freopen("girl.in","r",stdin);freopen("girl.out","w",stdout); work(); return 0; }