传送门

线段树合并菜题(然而findfindfind函数写错位置调了好久)

支持的操作题目写的很清楚了,然后有一个神奇的限制c≤7c\le7c≤7要注意到不然会去想毒瘤线段树的做法。


思路:

这题只有一个新奇的操作就是比较两个连通块的所有点权的乘积的大小。

这个东西可以对所有点权取对数之后转化为比较加和的大小。

剩下的都可以用并查集+线段树合并秒掉。

注意题目卡空间

代码:

#include<bits/stdc++.h>
#define lc (son[p][0])
#define rc (son[p][1])
#define ri register int
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
const int N=4e5+5;
struct Npde{int op,a,b;}qry[N];
int son[N*18][2],siz[N*18],tot=0,rt[N],fa[N],mp[N],n,m,cnt=0;
double val[N*18];
bool tag[N*18];
inline void pushup(int p){siz[p]=siz[lc]+siz[rc],val[p]=val[lc]+val[rc];}
inline void pushnow(int p){val[p]=siz[p]=0,tag[p]=1;}
inline void pushdown(int p){if(tag[p])pushnow(lc),pushnow(rc),tag[p]=0;}
inline void build(int&p,int l,int r,int k,int v1,double v2){
	if(!p)p=++tot;
	if(l==r){siz[p]=v1,val[p]=v2;return;}
	int mid=l+r>>1;
	pushdown(p);
	k<=mid?build(lc,l,mid,k,v1,v2):build(rc,mid+1,r,k,v1,v2);
	pushup(p);
}
inline int merge(int x,int y,int l,int r){
	if(!x||!y)return x+y;
	siz[x]+=siz[y],val[x]+=val[y];
	if(l==r)return x;
	int mid=l+r>>1;
	pushdown(x),pushdown(y);
	son[x][0]=merge(son[x][0],son[y][0],l,mid);
	son[x][1]=merge(son[x][1],son[y][1],mid+1,r);
	return x;
}
inline int query(int p,int l,int r,int ql,int qr){
	if(!p||ql>r||qr<l)return 0;
	if(ql<=l&&r<=qr)return siz[p];
	int mid=l+r>>1;
	pushdown(p);
	if(qr<=mid)return query(lc,l,mid,ql,qr);
	if(ql>mid)return query(rc,mid+1,r,ql,qr);
	return query(lc,l,mid,ql,mid)+query(rc,mid+1,r,mid+1,qr);
}
inline void update(int p,int l,int r,int ql,int qr){
	if(!p||ql>r||qr<l)return;
	if(ql<=l&&r<=qr)return pushnow(p);
	int mid=l+r>>1;
	pushdown(p);
	if(qr<=mid)update(lc,l,mid,ql,qr);
	else if(ql>mid)update(rc,mid+1,r,ql,qr);
	else update(lc,l,mid,ql,mid),update(rc,mid+1,r,mid+1,qr);
	pushup(p);
}
inline int ask(int p,int l,int r,int k){
	if(l==r)return l;
	int mid=l+r>>1;
	pushdown(p);
	if(siz[lc]>=k)return ask(lc,l,mid,k);
	return ask(rc,mid+1,r,k-siz[lc]);
}
inline int find(int x){return x==fa[x]?fa[x]:fa[x]=find(fa[x]);}
inline int idx(int x){return lower_bound(mp+1,mp+n+1,x)-mp;}
int main(){
	m=read();
	for(ri i=1;i<=m;++i){
		qry[i].op=read(),qry[i].a=read();
		if(qry[i].op!=1&&qry[i].op!=7)qry[i].b=read();
		if(qry[i].op==1)mp[++n]=qry[i].a;
		if(qry[i].op==3||qry[i].op==4)mp[++n]=qry[i].b;
	}
	sort(mp+1,mp+n+1),n=unique(mp+1,mp+n+1)-mp-1;
	for(ri i=1;i<=m;++i){
		switch(qry[i].op){
			case 1:build(rt[++cnt],1,n,idx(qry[i].a),1,log2(qry[i].a)),fa[cnt]=cnt;break;
			case 2:{
				int fx=find(qry[i].a),fy=find(qry[i].b);
				if(fx^fy)fa[fy]=fx,rt[fx]=merge(rt[fx],rt[fy],1,n);
				break;
			}
			case 3:{
				int fx=find(qry[i].a);
				int p=idx(qry[i].b),s=query(rt[fx],1,n,1,p);
				update(rt[fx],1,n,1,p),build(rt[fx],1,n,p,s,s*log2(qry[i].b));
				break;
			}
			case 4:{
				int fx=find(qry[i].a);
				int p=idx(qry[i].b),s=query(rt[fx],1,n,p,n);
				update(rt[fx],1,n,p,n),build(rt[fx],1,n,p,s,s*log2(qry[i].b));
				break;
			}
			case 5:cout<<mp[ask(rt[find(qry[i].a)],1,n,qry[i].b)]<<'\n';break;
			case 6:cout<<(val[rt[find(qry[i].a)]]>val[rt[find(qry[i].b)]])<<'\n';break;
			case 7:cout<<siz[rt[find(qry[i].a)]]<<'\n';break;
		}
	}
	return 0;
}

2019.01.16 bzoj4399: 魔法少女LJJ(线段树合并)的更多相关文章

  1. BZOJ4399魔法少女LJJ——线段树合并+并查集

    题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...

  2. bzoj4399 魔法少女LJJ 线段树合并

    只看题面绝对做不出系列.... 注意到\(c \leqslant 7\),因此不会有删边操作(那样例删边干嘛) 注意到\(2, 5\)操作十分的有趣,启示我们拿线段树合并来做 操作\(7\)很好处理 ...

  3. bzoj4399 魔法少女LJJ 线段树合并+线段树二分+并查集

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4399 题解 毒瘤题 \(9\) 种操作还有支持动态图的连通性 仔细读题 $ c<=7$. ...

  4. 【BZOJ4399】魔法少女LJJ 线段树合并

    [BZOJ4399]魔法少女LJJ Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的 ...

  5. BZOJ 4399: 魔法少女LJJ 线段树合并 + 对数

    Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着 ...

  6. BZOJ.4399.魔法少女LJJ(线段树合并)

    BZOJ 注意\(c\leq7\)→_→ 然后就是裸的权值线段树+线段树合并了. 对于取\(\max/\min\)操作可以直接区间修改清空超出范围的值,然后更新到对应位置上就行了(比如对\(v\)取\ ...

  7. 魔法少女 LJJ——线段树

    题目 [题目描述] 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女 LJJ 已经觉得自己见过世界上的所有稀奇古怪的事情了. LJJ 感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处 ...

  8. BZOJ 4399: 魔法少女LJJ(线段树)

    传送门 解题思路 出题人真会玩..操作\(2\)线段树合并,然后每棵线段树维护元素个数和.对于\(6\)这个询问,因为乘积太大,所以要用对数.时间复杂度\(O(nlogn)\) 代码 #include ...

  9. 2019.01.16 bzoj3526: [Poi2014]Card(线段树)

    传送门 线段树菜题. 题意:有一些卡牌,正反各有一个数,你可以任意翻转,每次操作会将两张卡牌的位置调换,你需要在每次操作后回答以现在的卡牌顺序能否通过反转形成一个单调不降的序列. 思路: 对于一个线段 ...

随机推荐

  1. 微信小程序开发——点击按钮获取用户授权没反应或反应很慢的解决方法

    异常描述: 点击按钮获取用户手机号码,有的时候会出现点击无反应或很久之后才弹出用户授权获取手机号码的弹窗,这种情况下,也会出现点击穿透的问题(详见:微信小程序开发——连续快速点击按钮调用小程序api返 ...

  2. 无法打开这些文件internet安全设置

    在安装别人传过来的软件的时候 出现这种情况 解决: 对这个程序,右键“属性”,可以看到属性窗口下方提示:此文件来自其它的电脑,可能不安全,后面有个按钮“解除锁定”

  3. swift - layer - 渐变色 - CAGradientLayer

    1.创建 渐变色 /// 渐变色:默认从上到下 private var gradientLayer: CAGradientLayer = { let g = CAGradientLayer() g.c ...

  4. C++ 读取文本文件内容到结构体数组中并排序

    成绩排行:从Score.txt文件读取学生信息,对其进行排序,按回答题数从大到小排,若相等,按分数从小到大排 #include<iostream> #include<fstream& ...

  5. Struts2框架之Action类的访问

    1. 通过<action>标签中的method属性,访问到Action中的具体的方法. * 传统的配置方式,配置更清晰更好理解!但是扩展需要修改配置文件等! * 具体的实例如下: * 页面 ...

  6. 转换 transform

    转换 定义: 1.转换是使元素改变形状.尺寸和位置的一种效果 2.又称为变形,即,可以向元素应用 2D 或 3D 转换,从而对元素进行旋转.缩放.移动或倾斜 3.2D转换:使元素在 X 轴和 Y 轴平 ...

  7. Ubuntu安装R及R包

    安装R $sudo apt-get update $sudo apt-get install r-base $sudo apt-get install r-base-dev 安装一些可能的依赖包 $s ...

  8. sqli-labs:17,增删改

    增 insert into users values(','lcamry','lcamry'); 删 delete from users where id=16 删数据库:drop database ...

  9. 解决linux ubuntu不能识别华为手机的问题--升级内核

    敝人手中有一个华为mate8,但是debian, ubuntu及一系列衍生版均不能识别.只能识别出一个华为手机助手,但是无法使用华为的内置存贮. 在fedora上是可以完美使用的. 归根到底的原因,是 ...

  10. docker下安装tomcat

    一,查看tomcat镜像 [root@icompany ~]# docker search tomcat INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED ...