传送门


IOI强行交互可还行,我Luogu的代码要改很多才能交到UOJ去……

发现问题是对边权做限制的连通块类问题,考虑\(Kruskal\)重构树进行解决。

对于图上的边\((u,v)(u<v)\),我们建两棵\(Kruskal\)重构树,一棵按照\(u\)从大到小加边表示人形时的活动区域,一棵按照\(v\)从小到大加边表示狼形时的活动区域。

那么我们的每组询问就变为了:给出两段区间,询问是否存在一个点同时覆盖这两个区间(即人形转换为狼形的地点)。这个是经典的二维数点问题,使用主席树计算即可。

话说感觉一堆namespace的码风看起来好舒服啊~

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c)){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    while(isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 2e5 + 10;
int N , M , Q;
namespace ST{
#define mid ((l + r) >> 1)
    struct node{
        int l , r , sum;
    }Tree[MAXN * 50];
    int root[MAXN] , cnt;

    void insert(int& x , int p , int l , int r , int tar){
        x = ++cnt;
        Tree[x] = Tree[p];
        ++Tree[x].sum;
        if(l == r)
            return;
        if(mid >= tar)
            insert(Tree[x].l , Tree[p].l , l , mid , tar);
        else
            insert(Tree[x].r , Tree[p].r , mid + 1 , r , tar);
    }

    bool query(int x , int y , int l , int r , int L , int R){
        if(Tree[x].sum == Tree[y].sum)
            return 0;
        if(l >= L && r <= R)
            return 1;
        bool f = 0;
        if(mid >= L)
            f |= query(Tree[x].l , Tree[y].l , l , mid , L , R);
        if(!f && mid < R)
            f |= query(Tree[x].r , Tree[y].r , mid + 1 , r , L , R);
        return f;
    }
}

namespace Itst{
#define P pair < int , int >
    int fa[2][MAXN << 1] , ch[2][MAXN << 1][2] , jump[2][MAXN << 1][21] , que[2][MAXN << 1] , dfn[2][MAXN] , cnt[2] , ts[2] , rg[2][MAXN << 1][2];

    void init(){
        cnt[0] = cnt[1] = N;
        for(int i = 1 ; i <= N ; ++i)
            fa[0][i] = fa[1][i] = i;
    }

    int find(int ind , int x){
        return fa[ind][x] == x ? x : (fa[ind][x] = find(ind , fa[ind][x]));
    }

    inline void link(int ind , int x , int y){
        x = find(ind , x);
        y = find(ind , y);
        if(x == y)
            return;
        ++cnt[ind];
        fa[ind][x] = fa[ind][y] = fa[ind][cnt[ind]] = cnt[ind];
        ch[ind][cnt[ind]][0] = x;
        ch[ind][cnt[ind]][1] = y;
    }

    void dfs(int ind , int x , int p){
        jump[ind][x][0] = p;
        for(int i = 1 ; jump[ind][x][i - 1] ; ++i)
            jump[ind][x][i] = jump[ind][jump[ind][x][i - 1]][i - 1];
        if(x <= N){
            rg[ind][x][0] = rg[ind][x][1] = dfn[ind][x] = ++ts[ind];
            que[ind][x] = x;
            return;
        }
        dfs(ind , ch[ind][x][0] , x);
        dfs(ind , ch[ind][x][1] , x);
        que[ind][x] = ind ? min(que[ind][ch[ind][x][0]] , que[ind][ch[ind][x][1]]) : max(que[ind][ch[ind][x][0]] , que[ind][ch[ind][x][1]]);
        rg[ind][x][0] = rg[ind][ch[ind][x][0]][0];
        rg[ind][x][1] = rg[ind][ch[ind][x][1]][1];
    }

    int up(int ind , int x , int l , int r){
        for(int i = 19 ; i >= 0 ; --i)
            if(jump[ind][x][i] && que[ind][jump[ind][x][i]] >= l && que[ind][jump[ind][x][i]] <= r)
                x = jump[ind][x][i];
        return x;
    }

    void work(){
        dfs(0 , cnt[0] , 0);
        dfs(1 , cnt[1] , 0);
        vector < P > p;
        for(int i = 1 ; i <= N ; ++i)
            p.push_back(P(dfn[0][i] , dfn[1][i]));
        sort(p.begin() , p.end());
        for(int i = 1 ; i <= N ; ++i)
            ST::insert(ST::root[i] , ST::root[i - 1] , 1 , N , p[i - 1].second);

        while(Q--){
            int S = read() + 1 , E = read() + 1 , L = read() + 1 , R = read() + 1;
            E = up(0 , E , 1 , R);
            S = up(1 , S , L , N);
            puts(ST::query(ST::root[rg[0][E][1]] , ST::root[rg[0][E][0] - 1] , 1 , N , rg[1][S][0] , rg[1][S][1]) ? "1" : "0");
        }
    }
}

namespace init{
    struct Edge{
        int a , b;
    }Ed[MAXN << 1];

    bool cmp1(Edge a , Edge b){
        return a.b < b.b;
    }

    bool cmp2(Edge a , Edge b){
        return a.a > b.a;
    }

    void main(){
        N = read();
        M = read();
        Q = read();
        Itst::init();
        for(int i = 1 ; i <= M ; ++i){
            Ed[i].a = read() + 1;
            Ed[i].b = read() + 1;
            if(Ed[i].a > Ed[i].b)
                swap(Ed[i].a , Ed[i].b);
        }
        sort(Ed + 1 , Ed + M + 1 , cmp1);
        for(int i = 1 ; i <= M ; ++i)
            Itst::link(0 , Ed[i].a , Ed[i].b);
        sort(Ed + 1 , Ed + M + 1 , cmp2);
        for(int i = 1 ; i <= M ; ++i)
            Itst::link(1 , Ed[i].a , Ed[i].b);
        Itst::work();
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
#endif
    init::main();
    return 0;
}

Luogu4899 IOI2018 Werewolf 主席树、Kruskal重构树的更多相关文章

  1. Kruskal重构树入门

    这个知识点好像咕咕咕了好长了..趁还没退役赶紧补一下吧.. 讲的非常简略,十分抱歉.. 前置知识 Kruskal算法 一定的数据结构基础(如主席树) Kruskal重构树 直接bb好像不是很好讲,那就 ...

  2. [IOI2018] werewolf 狼人 kruskal重构树,主席树

    [IOI2018] werewolf 狼人 LG传送门 kruskal重构树好题. 日常安利博客文章 这题需要搞两棵重构树出来,这两棵重构树和我们平时见过的重构树有点不同(据说叫做点权重构树?),根据 ...

  3. [IOI2018] werewolf 狼人 [kruskal重构树+主席树]

    题意: 当你是人形的时候你只能走 \([L,N-1]\) 的编号的点(即大于等于L的点) 当你是狼形的时候你只能走 \([1,R]\) 的编号的点(即小于等于R的点) 然后问题转化成人形和狼形能到的点 ...

  4. UOJ#407. 【IOI2018】狼人 Kruskal,kruskal重构树,主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ407.html 题解 套路啊. 先按照两个节点顺序各搞一个kruskal重构树,然后问题转化成两棵krus ...

  5. LOJ.2865.[IOI2018]狼人(Kruskal重构树 主席树)

    LOJ 洛谷 这题不就是Peaks(加强版)或者归程么..这算是\(IOI2018\)撞上\(NOI2018\)的题了? \(Kruskal\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...

  6. 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1202  Solved: 321[Submit][Sta ...

  7. BZOJ 3551: [ONTAK2010]Peaks加强版 [Kruskal重构树 dfs序 主席树]

    3551: [ONTAK2010]Peaks加强版 题意:带权图,多组询问与一个点通过边权\(\le lim\)的边连通的点中点权k大值,强制在线 PoPoQQQ大爷题解传送门 说一下感受: 容易发现 ...

  8. bzoj 3551 kruskal重构树dfs序上的主席树

    强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...

  9. [IOI2018]狼人——kruskal重构树+可持久化线段树

    题目链接: IOI2018werewolf 题目大意:给出一张$n$个点$m$条边的无向图,点和边可重复经过,一个狼人初始为人形,有$q$次询问,每次询问要求人形态只能处于编号不小于$L$的点,狼形态 ...

随机推荐

  1. JSONArray.toJSONString json乱码

    前提:配置文件已经配置了: <mvc:annotation-driven> <!-- 处理请求返回json字符串的中文乱码问题 --> <mvc:message-conv ...

  2. SD从零开始67-70 后勤信息系统中的标准分析, 信息结构, 信息的更新规则, 建立统计数据

    SD从零开始67 后勤信息系统中的标准分析 标准分析中的报表Reporting in Standard Analyses 标准分析为高质量的表达和分析LIS中的数据基础提供了大量的功能: 当你决定了一 ...

  3. Ado.net 访问Oracle乱码问题

    之前安装Oracle - OraClient10g_home1客户端,用Ado.net访问没有问题,后来安装ODP之后,自动的又安装了Oracle - OraClient12Home1,之后就出现乱码 ...

  4. 安卓开发-设置RadioButton的点击效果

    在安卓开发中用到底部菜单栏 需要用到RadioButton这个组件 实际应用的过程中,需要对按钮进行点击,为了让用户知道是否点击可这个按钮,可以设置点击后 ,该按钮的颜色或者背景发生变化. layou ...

  5. [Kali_Debian] 清除无用的库文件(清理系统,洁癖专用)-布布扣-bubuko.com - Google Chrome

    [Kali_Debian] 清除无用的库文件(清理系统,洁癖专用) 时间:2014-11-07 16:25:36      阅读:1486      评论:0      收藏:0      [点我收藏 ...

  6. Javascript 高级程序设计--总结【二】

    **********************  Chapter 6  ********************** 属性: 数据属性: Configurable: 能否通过delete 删除属性,默认 ...

  7. Fedora 28 打印机配置 ( HP pro 1136M ,基于Windows 打印服务器使用 smb 协议)

    Fedora 28 本身是没有打印服务的.我们需要安装下列软件: System-Config-Printer Common Unix Printing System - CUPS hplip.x86_ ...

  8. Matplotlib:可视化颜色命名分类和映射颜色分类

    Matplotlib中支持的所有颜色分类 映射颜色分类

  9. 【19】Linux系统知识点

    一.积跬步以致千里,积怠情以致深渊 二.目录结构

  10. Word中类似正则匹配的查找替换通配符的使用详解

    一.Word查找栏代码&通配符一览表 序号 清除使用通配符复选框 勾选使用通配符复选框 特殊字符 代码 特殊字符 代码or通配符 1 任意单个字符 ^? 任意单个字符 ? 2 任意数字 ^# ...