分析

直线都是\(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. 经典面试题sql基础篇-50常用的sql语句(有部分错误)

    Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,Tname) 教师表 问题 ...

  2. JavaScript+CSS+DIV实现下拉菜单示例

    <!DOCTYPE html> <html> <head> <title>下拉菜单示例</title> <script languag ...

  3. JavaScript作用域及作用域链详解、声明提升

    相信大家在入门JavaScript这门语言时对作用域.作用域链.变量声明提升这些概念肯定会稀里糊涂,下面就来说说这几个 Javascript 作用域 在 Javascript 中,只有局部作用域和全局 ...

  4. 如何正确认识Docker Kubernetes 和 Apache Mesos

    参考链接: http://geek.csdn.net/news/detail/229382

  5. 前端关于列表的基础 day47

    <!DOCTYPE html><html lang="zh-CN"><head> <meta charset="utf-8&qu ...

  6. shell日常实战防dos攻击

    根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到100,即调用防火墙命令封掉对应的IP,监控频率每隔3分钟.防火墙命令为:iptables -I INPUT -s 10.0 ...

  7. REST easy with kbmMW #17 – Database 6 – Existing databases

    kbmMW已经包含了非常精细的功能来确定和解释数据库中表的元数据. 在下一版本中,这个功能将得到进一步加强,可以导入现有数据库中的表,自动创建与表相匹配的ORM实体类. 这意味着你能够使用kbmMW的 ...

  8. 你知道怎么用Idea抽取方法、创建class吗?

    liJ IDEA的快捷键是进行重构的利器,坊间盛传,完全使用IDEA快捷键重构的代码,是不需要写测试用例保护的 本文就分享一个使用IDEA抽取方法及创建新的class的方法 工具/原料   Intel ...

  9. JAVA测试编程

    本周我们上JAVA课的时候进行了一次测试,本次测试以模拟中国工商银行自助机ATM的功能为大致要求,要求我们进行编写调试,以求达到试题要求. 测试要求我们能模拟ATM的功能设计,当用户插卡后显示,输入密 ...

  10. POWER BI报表服务器混合云初了解

    Power BI报表服务器 购买Power BI Premium时,你可以获取2个产品,一个是Power BI Service另外一个是Power BI Report Server. Power BI ...