感谢线段树进阶,给了我重新做人的机会。---------------某不知名OIer,Keen_z

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很郁闷,你能帮帮他吗

输入格式

第一行有一个正整数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点的所有连边 具体输出格式见样例

HINT

对100%的数据 0<=m<=400000,c<=7,所有出现的数均<=1000000000,所有出现的点保证存在 【HINT】请认真阅读题面

Solution

给了8,9两个阴间删点删边操作之后告诉你c<=7。。

一个很喵的转化,可以将连乘转化为对数之和。

数据最大1e9,显然不能直接开线段树,需要离散化。

将每个联通块都看作一个线段树,在其中维护权值为i的点的个数与元素对数的和。连边时将两点所在的线段树合并。

过程中要用一波并察集操作,来及时更新合并后线段树的根。

主要还是看代码吧,应该挺好理解的(挺不好调的

附去掉9 1后的样例输入,输出应为5。


code:

#include<bits/stdc++.h>
#define debug cout<<"wrong"<<endl
using namespace std;
const int NN=4e5+5;
int hal,id,c[NN],rt[NN],m,dat[NN][3],has[NN],cnt,fa[NN],s;
double logg[NN];
inline signed read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
void write(int x){
if(x<0) putchar('-'), x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
int get(int x){
return fa[x]==x?x:fa[x]=get(fa[x]);
}
inline int cag(int x){
return lower_bound(has+1,has+1+hal,x)-has;
}
struct node{
int seg,ls[NN*20],rs[NN*20],caf[NN*20],siz[NN*20];
double sum[NN*20];
void pushup(int x){
sum[x]=sum[ls[x]]+sum[rs[x]];
siz[x]=siz[ls[x]]+siz[rs[x]];
}
void insert(int &x,int l,int r,int pos,int w){
if(!x) x=++seg;
if(l==r){
sum[x]+=logg[pos]*w;
siz[x]+=w;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) insert(ls[x],l,mid,pos,w);
else insert(rs[x],mid+1,r,pos,w);
pushup(x);
}
int query(int x,int l,int r,int pos){
if(l==r) return l;
int mid=(l+r)>>1;
if(siz[ls[x]]>=pos) return query(ls[x],l,mid,pos);
else return query(rs[x],mid+1,r,pos-siz[ls[x]]);
}
void marge(int &x,int y,int l,int r){
if(!x||!y){
x=x+y;
return;
}
if(l==r){
siz[x]+=siz[y];
sum[x]+=sum[y];
return;
}
int mid=(l+r)>>1;
marge(ls[x],ls[y],l,mid);
marge(rs[x],rs[y],mid+1,r);
pushup(x);
}
void delet(int x,int l,int r,int opl,int opr){
if(!siz[x]) return;
if(l==r){
s+=siz[x];
sum[x]=siz[x]=0;
return;
}
int mid=(l+r)>>1;
if(opl<=mid) delet(ls[x],l,mid,opl,opr);
if(opr>mid) delet(rs[x],mid+1,r,opl,opr);
pushup(x);
}
}segt;
int main(){
m=read();
for(int i=1;i<=m;i++){
c[i]=read(); dat[i][1]=read();
if(c[i]!=1&&c[i]!=7) dat[i][2]=read();
if(c[i]==1) has[++cnt]=dat[i][1], dat[i][2]=++id;
if(c[i]==3||c[i]==4) has[++cnt]=dat[i][2];
}
sort(has+1,has+cnt+1);
hal=unique(has+1,has+cnt+1)-(has+1);
for(int i=1;i<=m;i++)
switch(c[i]){
case 1:{
int x=cag(dat[i][1]);
logg[x]=log(dat[i][1]);
segt.insert(rt[dat[i][2]],1,hal,x,1);
fa[dat[i][2]]=dat[i][2];
break;
}
case 2:{
int rx=get(dat[i][1]),ry=get(dat[i][2]);
if(rx!=ry){
fa[ry]=rx;
segt.marge(rt[rx],rt[ry],1,hal);
}
break;
}
case 3:{
int x=cag(dat[i][2]),ro=get(dat[i][1]);
s=0; logg[x]=log(dat[i][2]);
segt.delet(rt[ro],1,hal,1,max(1,x-1));
if(s) segt.insert(rt[ro],1,hal,x,s);
break;
}
case 4:{
int x=cag(dat[i][2]),ro=get(dat[i][1]);
s=0; logg[x]=log(dat[i][2]);
segt.delet(rt[ro],1,hal,min(hal,x+1),hal);
if(s) segt.insert(rt[ro],1,hal,x,s);
break;
}
case 5:{
int ro=get(dat[i][1]);
int ans=segt.query(rt[ro],1,hal,dat[i][2]);
write(has[ans]); putchar('\n');
break;
}
case 6:{
int r1=get(dat[i][1]),r2=get(dat[i][2]);
if(segt.sum[rt[r1]]>segt.sum[rt[r2]]) puts("1");
else puts("0");
break;
}
case 7:{
int ro=get(dat[i][1]);
write(segt.siz[rt[ro]]); putchar('\n');
break;
}
}
}
/*
11
1 2
1 3
1 4
1 5
1 6
2 1 2
2 2 3
2 3 4
2 4 5
3 2 5
5 3 4
*/

Code

  1 #include<bits/stdc++.h>
2 #define debug cout<<"lbwnb"<<endl
3 using namespace std;
4 const int NN=4e5+5;
5 int hal,id,c[NN],rt[NN],m,dat[NN][3],has[NN],cnt,fa[NN],s;
6 double logg[NN];
7 inline signed read(){
8 int x=0,f=1;
9 char ch=getchar();
10 while(ch<'0'||ch>'9')
11 {
12 if(ch=='-') f=-1;
13 ch=getchar();
14 }
15 while(ch<='9'&&ch>='0')
16 {
17 x=(x<<1)+(x<<3)+(ch^48);
18 ch=getchar();
19 }
20 return x*f;
21 }
22 void write(int x){
23 if(x<0) putchar('-'), x=-x;
24 if(x>9) write(x/10);
25 putchar(x%10+'0');
26 }
27 int get(int x){
28 return fa[x]==x?x:fa[x]=get(fa[x]);
29 }
30 inline int cag(int x){
31 return lower_bound(has+1,has+1+hal,x)-has;
32 }
33 struct node{
34 int seg,ls[NN*20],rs[NN*20],caf[NN*20],siz[NN*20];
35 double sum[NN*20];
36 void pushup(int x){
37 sum[x]=sum[ls[x]]+sum[rs[x]];
38 siz[x]=siz[ls[x]]+siz[rs[x]];
39 }
40 void insert(int &x,int l,int r,int pos,int w){
41 if(!x) x=++seg;
42 if(l==r){
43 sum[x]+=logg[pos]*w;
44 siz[x]+=w;
45 return;
46 }
47 int mid=(l+r)>>1;
48 if(pos<=mid) insert(ls[x],l,mid,pos,w);
49 else insert(rs[x],mid+1,r,pos,w);
50 pushup(x);
51 }
52 int query(int x,int l,int r,int pos){
53 if(l==r) return l;
54 int mid=(l+r)>>1;
55 if(siz[ls[x]]>=pos) return query(ls[x],l,mid,pos);
56 else return query(rs[x],mid+1,r,pos-siz[ls[x]]);
57 }
58 void marge(int &x,int y,int l,int r){
59 if(!x||!y){
60 x=x+y;
61 return;
62 }
63 if(l==r){
64 siz[x]+=siz[y];
65 sum[x]+=sum[y];
66 return;
67 }
68 int mid=(l+r)>>1;
69 marge(ls[x],ls[y],l,mid);
70 marge(rs[x],rs[y],mid+1,r);
71 pushup(x);
72 }
73 void delet(int x,int l,int r,int opl,int opr){
74 if(!siz[x]) return;
75 if(l==r){
76 s+=siz[x];
77 sum[x]=siz[x]=0;
78 return;
79 }
80 int mid=(l+r)>>1;
81 if(opl<=mid) delet(ls[x],l,mid,opl,opr);
82 if(opr>mid) delet(rs[x],mid+1,r,opl,opr);
83 pushup(x);
84 }
85 }segt;
86 int main(){
87 m=read();
88 for(int i=1;i<=m;i++){
89 c[i]=read(); dat[i][1]=read();
90 if(c[i]!=1&&c[i]!=7) dat[i][2]=read();
91 if(c[i]==1) has[++cnt]=dat[i][1], dat[i][2]=++id;
92 if(c[i]==3||c[i]==4) has[++cnt]=dat[i][2];
93 }
94 sort(has+1,has+cnt+1);
95 hal=unique(has+1,has+cnt+1)-(has+1);
96 for(int i=1;i<=m;i++)
97 switch(c[i]){
98 case 1:{
99 int x=cag(dat[i][1]);
100 logg[x]=log(dat[i][1]);
101 segt.insert(rt[dat[i][2]],1,hal,x,1);
102 fa[dat[i][2]]=dat[i][2];
103 break;
104 }
105 case 2:{
106 int rx=get(dat[i][1]),ry=get(dat[i][2]);
107 if(rx!=ry){
108 fa[ry]=rx;
109 segt.marge(rt[rx],rt[ry],1,hal);
110 }
111 break;
112 }
113 case 3:{
114 int x=cag(dat[i][2]),ro=get(dat[i][1]);
115 s=0; logg[x]=log(dat[i][2]);
116 segt.delet(rt[ro],1,hal,1,max(1,x-1));
117 if(s) segt.insert(rt[ro],1,hal,x,s);
118 break;
119 }
120 case 4:{
121 int x=cag(dat[i][2]),ro=get(dat[i][1]);
122 s=0; logg[x]=log(dat[i][2]);
123 segt.delet(rt[ro],1,hal,min(hal,x+1),hal);
124 if(s) segt.insert(rt[ro],1,hal,x,s);
125 break;
126 }
127 case 5:{
128 int ro=get(dat[i][1]);
129 int ans=segt.query(rt[ro],1,hal,dat[i][2]);
130 write(has[ans]); putchar('\n');
131 break;
132 }
133 case 6:{
134 int r1=get(dat[i][1]),r2=get(dat[i][2]);
135 if(segt.sum[rt[r1]]>segt.sum[rt[r2]]) puts("1");
136 else puts("0");
137 break;
138 }
139 case 7:{
140 int ro=get(dat[i][1]);
141 write(segt.siz[rt[ro]]); putchar('\n');
142 break;
143 }
144 }
145 }
146 /*
147 11
148 1 2
149 1 3
150 1 4
151 1 5
152 1 6
153 2 1 2
154 2 2 3
155 2 3 4
156 2 4 5
157 3 2 5
158 5 3 4

[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. 魔法少女 LJJ——线段树

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

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

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

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

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

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

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

  9. BZOJ4399 魔法少女LJJ【线段树合并】【并查集】

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

随机推荐

  1. python动态网站爬虫实战(requests+xpath+demjson+redis)

    目录 前言 一.主要思路 1.观察网站 2.编写爬虫代码 二.爬虫实战 1.登陆获取cookie 2.请求资源列表页面,定位获得左侧目录每一章的跳转url(难点) 3.请求每个跳转url,定位右侧下载 ...

  2. 用python的pandas读取excel文件中的数据

    一.读取Excel文件   使用pandas的read_excel()方法,可通过文件路径直接读取.注意到,在一个excel文件中有多个sheet,因此,对excel文件的读取实际上是读取指定文件.并 ...

  3. Python脚本运行出现语法错误:IndentationError:unexpected indent

    对于py来说典型错误就是缩进,,烦不胜烦,整理一下解决方法:一个python脚本,本来都运行好好的,然后写了几行代码,而且也都确保每行都对齐了,但是运行的时候,却出现语法错误: Indentation ...

  4. python语言介绍及安装

    Python语言简介 Python是什么语言 Python是一种解释型的.可移植的.开源的脚本. 什么是计算机编程 计算机程序:为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合 如何 ...

  5. RestFul的认识与详解

    RestFul :是一种软件架构风格,设计风格,而不是标准.提供了一组设计原则和约束条件. 简单概述: REST -- REpresentational State Transfer 直接翻译:表现层 ...

  6. PHP中的输出缓冲控制

    在 PHP 中,我们直接进行 echo . 或者 print_r 的时候,输出的内容就会直接打印出来.但是,在某些情况下,我们并不想直接打印,这个时候就可以使用输出缓冲控制来进行输出打印的控制.当然, ...

  7. mysql将语句写入表中

    使用create table语句即可 CREATE TABLE membertmp (select a.* from member as a where a.phone <> '' and ...

  8. 配置php redis 扩展

    参照runoob:PHP 使用 Redis Windows: - 假设redis已经安装好 服务启动 - xampp (php 7.1 x86 windows) 查看phpinfo (php 7.1 ...

  9. python学习笔记(五)-文件操作2

    一.文件修改 现有文件file.txt,内容如下:二十四节气歌春雨惊春清谷天,夏满芒夏暑相连.秋处露秋寒霜降,冬雪雪冬小大寒.上半年逢六廿一,下半年逢八廿三.每月两节日期定,最多相差一二天.要求:将文 ...

  10. P3343-[ZJOI2015]地震后的幻想乡【dp,数学期望】

    正题 题目链接:https://www.luogu.com.cn/problem/P3343 题目大意 给出\(n\)个点的一张无向图,每条边被修复的时间是\([0,1]\)的一个随机实数,求这张图联 ...