bzoj4399: 魔法少女LJJ
题目描述
在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女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很郁闷,你能帮帮他吗
输入格式
第一行有一个正整数m,表示操作个数。 接下来m行,每行先给出1个正整数c。 若c=1,之后一个正整数x,表示新建一个权值为x的节点,并且节点编号为n+1(当前有n个节点)。 若c=2,之后两个正整数a,b,表示在a,b之间连接一条边。 若c=3,之后两个正整数a,x,表示a联通快内原本权值小于x的节点全部变成x。 若c=4,之后两个正整数a,x,表示a联通快内原本权值大于x的节点全部变成x。 若c=5,之后两个正整数a,k,表示询问a所属于的联通块内的第k小的权值是多少。 若c=6,之后两个正整数a,b,表示询问a所属联通快内所有节点权值之积与b所属联通快内所有节点权值之积的大小, 若a所属联通快内所有节点权值之积大于b所属联通快内所有节点权值之积,输出1,否则为0。 若c=7,之后一个正整数a,表示询问a所在联通块大小 若c=8,之后两个正整数a,b,表示断开a,b所连接的边。 若c=9,之后一个正整数a,表示断开a点的所有连边 具体输出格式见样例
样例
样例输入
12
1 2
1 3
1 4
1 5
1 6
2 1 2
2 2 3
2 3 4
2 4 5
9 1
3 2 5
5 3 4
样例输出
6
数据范围与提示
对100%的数据 0<=m<=400000,c<=7,所有出现的数均<=1000000000,所有出现的点保证存在 【HINT】请认真阅读题面
先认真看题面,c<=7,故不用考虑断边和删点,而其他的操作均和联通块有关,即不必考虑连边情况,只用考虑整个联通块的情况,也就是用并查集
进一步看各个操作,发现有权值的询问和修改操作,考虑到数据范围,使用O(mlogn)的动态开点权值线段树,对于连边操作,可以看成联通块合并,使用合并线段树同时维护并查集
由于权值可能远超点数,会对权值线段树有额外的时空花费,使用离散化并建立前后映射关系,以便于询问和修改
离散化后权值最大为m,多次求积有可能爆掉long long ,并且在求单点乘积时会有一定时间花销,考虑使用对数将 a b a^b ab转化为
b log a b \log a bloga,将 a ∗ b a*b a∗b 转化为 log a + log b \log a+\log b loga+logb
#include<bits/stdc++.h>
using namespace std;
const int N=400011;
struct tree{
int lc,rc,sum;
double pct;
}tre[N*30];
struct opt_{
int c,x,y,z;
}opt[N];
int pre[N],siz[N];
int tpre[N],root[N];
int n,m,tot;
int ls[N],num,lsh[N];
inline int read()
{
int s=0;
char ch=getchar();
while(ch>'9'||ch<'0')
ch=getchar();
while(ch>='0'&&ch<='9')
{
s=(s<<1)+(s<<3)+(ch^48);
ch=getchar();
}
return s;
}
int find(int x)
{
if(pre[x]==x)
return x;
return pre[x]=find(pre[x]);
}
int merge(int p,int q,int l,int r)
{
if(!p)
return q;
if(!q)
return p;
if(l==r)
{
tre[p].sum+=tre[q].sum;
if(tre[p].sum)
tre[p].pct=log(double(ls[l