分析

直线都是\(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. python 学习 map /reduce

    python 内建了map()和reduce()函数 map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回. ...

  2. macOS Sierra 如何打开任何来源

    1.打开应用程序-实用工具-终端: 2.复制以下代码(红色处注意是两个-)到终端中,回车(输入电脑密码): sudo spctl --master-disable 3.打开应用程序-系统偏好设置-安全 ...

  3. vue-router-4-编程式导航

    想要导航到不同的 URL,用 router.push 方法,会向 history 栈添加一个新的记录 <router-link> <==>router.push // 字符串 ...

  4. 从R-CNN到FAST-RCNN再到Faster R-CNN

    (Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks)   R-CNN: (1)输入测试图像: ...

  5. 1085 PAT单位排行

    每次 PAT 考试结束后,考试中心都会发布一个考生单位排行榜.本题就请你实现这个功能. 输入格式: 输入第一行给出一个正整数 N(≤10​^5​​),即考生人数.随后 N 行,每行按下列格式给出一个考 ...

  6. python23的区别-日常记录

    1. xrange:python3 中取消了range函数,把python2中的xrange重新命名为range,所以在python3中直接用range就行. 2. print:python3中pri ...

  7. centos6.5 vncserver

    yum install tigervnc tigervnc-server -y vncserver 又叫tigervnc 2.配置 vncserver vim /etc/sysconfig/vncse ...

  8. 第四十二课 KMP算法的应用

    思考: replace图解: 程序完善: DTString.h: #ifndef DTSTRING_H #define DTSTRING_H #include "Object.h" ...

  9. 奇妙的证明 —— 0! = 1(a^0=1)

    1. 0!=1 (n−1)!=n!n" role="presentation">(n−1)!=n!n(n−1)!=n!n 则: 0!=1!1=1" rol ...

  10. 2017-2018-2 20165228 实验三《敏捷开发与XP实践》实验报告

    2017-2018-2 20165228 实验三<敏捷开发与XP实践>实验报告 相关知识点 (一)敏捷开发与XP 通过 XP准则来表达: 沟通 :XP认为项目成员之间的沟通是项目成功的关键 ...