分析

直线都是\(y=\overline{a.5}\)这种形式,而只查询州和城市的个数,所以很容易想到对\(y\)轴做投影,然后转化为区间修改(加减)和单点查询,可以用线段树维护。至于每个州只会合并不会分裂,大小肯定是只增不减的,所以用并查集维护很方便。

算法流程

线段树维护区间的州和城市的个数,以及它们的标记。

并查集要维护它的大小,纵坐标范围。

  1. road A B:如果A、B本身同属一个州就不管,因为肯定有覆盖A、B纵坐标的路连接它们两个。否则先撤销A、B所属州对线段树的贡献,然后合并两个州,最后把并集的贡献加到线段树上。
  2. line C:我规定线段树上\([i,i]\)节点管辖\(y\)轴上\([i,i-1]\)区间,也就是\(y=\overline{(i-1).5}\)这条直线。那么此操作相当于查询\([C+0.5,C+0.5]\)这个节点。

时间复杂度

建树复杂度\(O(n\log n)\)。单次操作无论是road A B还是line C都是\(O(\log n)\)的,而有\(m\)次操作,所以总时间复杂度为\(O(n\log n+m \log n)\)。

代码

#include<iostream>
#include<cstdio>
#define reg register
#pragma GCC optimize(3)
template<typename T>T read(T&x)
{
T data=0;
int w=1;
char ch=getchar();
while(ch!='-'&&!isdigit(ch))
ch=getchar();
if(ch=='-')
w=-1,ch=getchar();
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return x=data*w;
}
using namespace std;
const int MAXN=1e5+1,MAXY=1e6+1; struct SegTree // leaf node i controls y=i->(i-1)
{
int sums,sumc;
int adds,addc;
}ST[MAXY<<2];
#define root ST[o]
#define lson ST[o<<1]
#define rson ST[o<<1|1]
inline void pushup(int o)
{
root.sums=lson.sums+rson.sums;
root.sumc=lson.sumc+rson.sumc;
} void build(int o,int l,int r)
{
if(l==r)
{
root.sums=root.sumc=0;
root.adds=root.addc=0;
return;
}
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);
root.adds=root.addc=0;
} inline void pushdown(int o,int l,int r)
{
int mid=(l+r)>>1;
if(root.adds)
{
lson.sums+=root.adds*(mid-l+1),
lson.adds+=root.adds;
rson.sums+=root.adds*(r-mid),
rson.adds+=root.adds;
root.adds=0;
}
if(root.addc)
{
lson.sumc+=root.addc*(mid-l+1),
lson.addc+=root.addc;
rson.sumc+=root.addc*(r-mid),
rson.addc+=root.addc;
root.addc=0;
}
} void addrg(int o,int l,int r,int ql,int qr,int state,int city)
{
if(ql<=l&&r<=qr)
{
root.sums+=state*(r-l+1),
root.adds+=state;
root.sumc+=city*(r-l+1),
root.addc+=city;
return;
}
pushdown(o,l,r);
int mid=(l+r)>>1;
if(ql<=mid)
addrg(o<<1,l,mid,ql,qr,state,city);
if(qr>=mid+1)
addrg(o<<1|1,mid+1,r,ql,qr,state,city);
pushup(o);
} SegTree querypt(int o,int l,int r,int q)
{
if(l==r)
return root;
pushdown(o,l,r);
int mid=(l+r)>>1;
if(q<=mid)
return querypt(o<<1,l,mid,q);
else if(q>=mid+1)
return querypt(o<<1|1,mid+1,r,q);
} struct Point
{
int x,y;
}P[MAXN];
typedef Point Range; int fa[MAXN],sz[MAXN];
Range rg[MAXN]; // y=x->y(x<y) int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
} inline void unite(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx==fy) return;
if(rg[fx].x+1<=rg[fx].y)
{
addrg(1,1,1e6,rg[fx].x+1,rg[fx].y,-1,-sz[fx]);
}
if(rg[fy].x+1<=rg[fy].y)
{
addrg(1,1,1e6,rg[fy].x+1,rg[fy].y,-1,-sz[fy]);
}
sz[fy]+=sz[fx],sz[fx]=0;
fa[fx]=fy;
rg[fy].x=min(rg[fy].x,rg[fx].x),rg[fy].y=max(rg[fy].y,rg[fx].y);
if(rg[fy].x+1<=rg[fy].y)
{
addrg(1,1,1e6,rg[fy].x+1,rg[fy].y,1,sz[fy]);
}// ->segtree bomb
} int main()
{
int T;
read(T);
while(T--)
{
build(1,1,1e6);
int n;
read(n);
for(reg int i=0;i<n;++i)
{
read(P[i].x);read(P[i].y);
fa[i]=i;
sz[i]=1;
rg[i].x=rg[i].y=P[i].y;
}
int m;
read(m);
for(reg int i=1;i<=m;++i)
{
char opt[10];
scanf("%s",opt);
if(opt[0]=='r')
{
int A,B;
read(A);read(B);
unite(A,B);
}
else if(opt[0]=='l')
{
double C;
scanf("%lf",&C);
C+=0.5;
SegTree t=querypt(1,1,1e6,C);
printf("%d %d\n",t.sums,t.sumc);
}
}
}
}

Hint

线段树大小还可以继续优化。

UVA1455 【Kingdom】的更多相关文章

  1. 【CF613D】Kingdom and its Cities 虚树+树形DP

    [CF613D]Kingdom and its Cities 题意:给你一棵树,每次询问给出k个关键点,问做多干掉多少个非关键点才能使得所有关键点两两不连通. $n,\sum k\le 10^5$ 题 ...

  2. 【CF687D】Dividing Kingdom II 线段树+并查集

    [CF687D]Dividing Kingdom II 题意:给你一张n个点m条边的无向图,边有边权$w_i$.有q个询问,每次给出l r,问你:如果只保留编号在[l,r]中的边,你需要将所有点分成两 ...

  3. 【CF613D】Kingdom and its Cities

    [CF613D]Kingdom and its Cities 题面 洛谷 题解 看到关键点当然是建虚树啦. 设\(f[x]\)表示以\(x\)为根的子树的答案,\(g[x]\)表示以\(x\)为根的子 ...

  4. 【CF613D】Kingdom and its Cities(虚树,动态规划)

    [CF613D]Kingdom and its Cities(虚树,动态规划) 题面 洛谷 CF 翻译洛谷上有啦 题解 每次构建虚树,首先特判无解,也就是关键点中存在父子关系. 考虑\(dp\),设\ ...

  5. SCI&EI 英文PAPER投稿经验【转】

    英文投稿的一点经验[转载] From: http://chl033.woku.com/article/2893317.html 1. 首先一定要注意杂志的发表范围, 超出范围的千万别投,要不就是浪费时 ...

  6. 【LA3523】 Knights of the Round Table (点双连通分量+染色问题?)

    Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in distress ...

  7. 我的Android进阶之旅------>Android【设置】-【语言和输入法】-【语言】列表中找到相应语言所对应的列表项

    今天接到一个波兰的客户说有个APP在英文状态下一切运行正常,但是当系统语言切换到波兰语言的时候,程序奔溃了.所以首先我得把系统的语言切换到波兰语,问题是哪个是波兰语呢? 我还真的不认识哪个列表项代表着 ...

  8. 【BZOJ3864】Hero meet devil DP套DP

    [BZOJ3864]Hero meet devil Description There is an old country and the king fell in love with a devil ...

  9. 【转载】How to develop your own Boot Loader【怎么样开发自己的bootloader】

    How to develop your own Boot Loader 怎么样开发自己的bootloader Table of content[目录] 1. Who may be interested ...

随机推荐

  1. 用大白菜U盘安装:[3]Ghost版Win7系统

    Ghost版Win7系统安装步骤: 1,先下载Ghost Win7系统到硬盘中,然后在U盘或其它硬盘根目录中新建一个GHO文件夹,注意:决不能把文件夹建在C盘(系统盘)中,然后用UltraISO或者W ...

  2. Java流对象理解

    马士兵老师,曾在Java的学习过程中,将Java的流比作管道,认为很贴切,在此笔者也建议读者在学习过程中作类似比喻,形象化的学习 Java根据数据流向的不同分为输入流和输出流: Java根据处理数据类 ...

  3. Java基础第4天

    程序结构(按执行流程划分) 顺序结构:整体上程序是顺序结构. 分支结构:if(如果有else,则必有一个会执行)switch-case 循环结构:for while do-while ,重点:嵌套循环 ...

  4. 在 子 iframe中 点击一个按钮, 变换 这个 iframe的地址url.

    //跳到测试结果: function jump() { console.log(self.parent.document.getElementById("iframe").src) ...

  5. django面试五

    http和https的区别https协议需要到ca申请证书,一般免费证书很少,需要交费. 注:CA - certificate authority,身份认证,权威机构认证,CA认证: http是超文本 ...

  6. 莫烦tensorflow(3)-Variable

    import tensorflow as tf state = tf.Variable(0,name='counter') one = tf.constant(1) new_value = tf.ad ...

  7. 1.selenium实战之从txt文档读取配置信息并执行登录

    前置条件: 1.本机已搭建ECShop3.0网站 2.在脚本目录创建了user.txt文本如下: 目的:实现从txt中读取配置文件信息,本实战中,包含url地址.用户名.密码,然后进行ESChop的登 ...

  8. 【Python】进程-锁(1)

    #第二题,做一个加减乘除的考试系统,自动出题,自动判对错,并统计结果,一次考试10道题 import random symbols=["+","-"," ...

  9. 构建工具 —— Groovy 与 Gradle

    1. Gradle Gradle 是一个基于 Groovy 的构建工具,使用 Groovy 来编写构建脚本,类似 maven,支持依赖管理和多项目创建. 相比 maven,更轻量: windows c ...

  10. 餐巾计划问题 zwk费用流解法

    «问题描述:一个餐厅在相继的N 天里,每天需用的餐巾数不尽相同.假设第i天需要ri块餐巾(i=1,2,…,N).餐厅可以购买新的餐巾,每块餐巾的费用为p分:或者把旧餐巾送到快洗部,洗一块需m天,其费用 ...