UVALive 4730 Kingdom

Kingdom

https://ac.nowcoder.com/acm/problem/121647

Kingdom

Kingdom - UVALive 4730 - Virtual Judge (vjudge.net)

题目描述

平面上有n个城市,初始时城市之间没有任何双向道路相连,你的任务是依次执行以下指令

road A B:在城市A和城市B之间链接一条双向道路,保证着条道路不和其他道路在非端点处相交

line C:询问一条y = C的水平线和多少个州以及这些州一共包含多少城市,每一组联通的城市形成一个州

样例

3
10
1 7
5 7
8 6
3 5
5 5
2 3
10 3
7 2
4 1
11 1
11
road 0 1
road 3 5
line 6.5
road 4 2
road 3 8
road 4 7
road 6 9
road 4 1
road 2 7
line 4.5
line 6.5
1
100 100
1
line 100.5
2
10 10
20 20
2
road 0 1
line 15.5
0 0
2 8
1 5
0 0
1 2

算法1

(线段树维护线段 + 并查集 + 区间覆盖次数)
  • 维护联通块和联通块的城市个数我们可以用并查集维护
  • 然后我们根据y轴建立线段树
  • 同时我们还需要维护每一个联通块在y轴上的范围,将每一个联通块抽象成线段
  • 某一个区间被线段覆盖多少次就意味着用一条水平线穿过该区间后能于多少个州相交
  • 所以我们维护两个信息(被线段覆盖次数),城市个数

时间复杂度

参考文献

C++ 代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
// #include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <bitset>
#include <cmath>
#include <map>

#define x first
#define y second

#define P 131

#define lc u << 1
#define rc u << 1 | 1

using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 100010,M = 1000010;
struct Node
{
    int l,r;
    int s1,s2;//s1州的数量,s2城市的数量
    int add1,add2;
}tr[M * 4];
int flag[M * 4];
int ks;
int p[N],sz[N];
PII range[N];
PII citys[N];
char str[10];
int n,m;

inline int find(int x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

inline void Flash(int u)
{
    if(flag[u] == ks) return;
    flag[u] = ks;
    tr[u].s1 = tr[u].s2 = tr[u].add1 = tr[u].add2 = 0;
}

inline int calc(int a,int b)
{
    return (b - a) + 1;
}

inline int calc(const PII &line)
{
    return calc(line.x,line.y);
}

inline void pushup(Node &rt,Node &left,Node &right)
{
    rt.s1 = left.s1 + right.s1;
    rt.s2 = left.s2 + right.s2;
}

inline void pushup(int u)
{
    Flash(lc);
    Flash(rc);
    pushup(tr[u],tr[lc],tr[rc]);
}

inline void pushdown(int u)
{
    if(tr[u].add1 != 0)
    {
        Flash(lc);
        Flash(rc);
        tr[lc].add1 += tr[u].add1;
        tr[rc].add1 += tr[u].add1;
        tr[lc].s1 += calc(tr[lc].l,tr[lc].r) * tr[u].add1;
        tr[rc].s1 += calc(tr[rc].l,tr[rc].r) * tr[u].add1;
        tr[u].add1 = 0;
    }
    if(tr[u].add2 != 0)
    {
        Flash(lc);
        Flash(rc);
        tr[lc].add2 += tr[u].add2;
        tr[rc].add2 += tr[u].add2;
        tr[lc].s2 += tr[u].add2;
        tr[rc].s2 += tr[u].add2;
        tr[u].add2 = 0;
    }
}

inline void build(int u,int l,int r)
{
    if(l == r)
    {
        tr[u] = Node({l,r,0,0,0,0});
        return;
    }
    int mid = (l + r )>> 1;
    tr[u] = Node({l,r,0,0,0,0});
    build(lc,l,mid);
    build(rc,mid + 1,r);
    pushup(u);
}

inline void modify(int u,int l,int r,int k1,int k2)
{
    Flash(u);
    if(tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].add1 += k1;
        tr[u].add2 += k2;
        tr[u].s1 += calc(tr[u].l,tr[u].r) * k1;
        tr[u].s2 += k2;
        return;
    }
    int mid = (tr[u].l + tr[u].r) >> 1;
    pushdown(u);
    if(l <= mid) modify(lc,l,r,k1,k2);
    if(r > mid) modify(rc,l,r,k1,k2);
    pushup(u);
}

inline Node query(int u,int x)
{
    Flash(u);
    if(tr[u].l == x && tr[u].r == x) return tr[u];
    int mid = (tr[u].l + tr[u].r) >> 1;
    pushdown(u);
    if(x <= mid) return query(lc,x);
    else return query(rc,x);
}

void solve()
{
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)
    {
        scanf("%d%d",&citys[i].x,&citys[i].y);
        p[i] = i,sz[i] = 1;
        range[i] = make_pair(citys[i].y,citys[i].y - 1);
    }
    scanf("%d",&m);
    while(m -- )
    {
        scanf("%s",str);
        if(str[0] == 'r')
        {
            int a,b;
            scanf("%d%d",&a,&b);
            a ++,b ++;
            int pa = find(a),pb = find(b);
            if(pa != pb)
            {
                if(calc(range[pa]) != 0) modify(1,range[pa].x,range[pa].y,-1,-sz[pa]);
                if(calc(range[pb]) != 0) modify(1,range[pb].x,range[pb].y,-1,-sz[pb]);
                p[pb] = pa;
                sz[pa] += sz[pb];
                range[pa].x = min(range[pa].x,range[pb].x);
                range[pa].y = max(range[pa].y,range[pb].y);
                if(calc(range[pa]) != 0) modify(1,range[pa].x,range[pa].y,1,sz[pa]);
                // cout << "------" << range[pa].x << " "<< range[pa].y << " "<< sz[pa] << endl;
            }
        }else
        {
            double c;
            scanf("%lf",&c);
            int t = (int)c;
            // cout <<"--"<< t << endl;
            Node tmp = query(1,t);
            printf("%d %d\n",tmp.s1,tmp.s2);
        }
    }
    ks ++;
} 

int main()
{
    int _ = 1;

    // freopen("network.in","r",stdin);
    // freopen("network.out","w",stdout);
    // init(N - 1); 

    // std::ios_base::sync_with_stdio(0);
    // cin.tie(0);
    // cin >> _;
    build(1,0,M - 1);//表示线段从0开始编号
    scanf("%d",&_);
    while(_ --)
    {
        // scanf("%lld%lld",&n,&m);
        solve();
        // test();
    }
    return 0;
}
全部评论

相关推荐

避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-10 12:05
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务