魔法少女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很郁闷,你能帮帮他吗
数据范围及提示:
$ 1\le m \le 4\times 10^{5},opt \le 7$
Solution:
我们会发现后面两种恶心到令人发指的操作根本不用实现(\(opt \le 7\))。也就是说,我们只需要合并两个联通块就好了,这让我们很难不想到并查集.
我们维护一些并查集以支持连边操作,然后每个并查集上开一颗权值线段树,每次连边就将两颗树合并。但是我们会发现乘积貌似有点难维护,但是题目只要求比大小,所以我们并不需要维护乘积的真实值,维护对数就好了。
然后修改操作就在 \([1,x-1]\) 或者是 \([x+1,inf]\) 区间上打上删除标记并且记录删除了多少个数字 \(tmp\),然后在 \(x\) 节点上添加 \(tmp\) 个点就好了。
细节提示:
由于这题的删除标记是要 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;
}
标签:4399,cnt,LJJ,val,int,权值,节点,BZOJ
From: https://www.cnblogs.com/LG017/p/18637692