[IOI2018] werewolf 狼人

[IOI2018] werewolf 狼人

IOI2018题解

代码:

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^‘0‘)
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch==‘-‘)&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int M=400000+5;
const int N=400000+5;
const int inf=0x3f3f3f3f;
int n,m,Q;
struct edge{
    int x,y;
    int val;
}b[M];
bool cmp0(edge a,edge b){
    return a.val<b.val;
}
bool cmp1(edge a,edge b){
    return a.val>b.val;
}
int fafa[2*N];

struct kruskal{
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[2*N],cnt;
    int fin(int x){
        return fafa[x]==x?x:fafa[x]=fin(fafa[x]);
    }
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int tot;
    void build(int typ){
        for(reg i=1;i<=n;++i){
            if(typ) val[i]=inf;
            else val[i]=-inf;
        }
        tot=n;
        for(reg i=1;i<=m;++i){
            int k1=fin(b[i].x),k2=fin(b[i].y);
    //        cout<<" edge "<<b[i].x<<" "<<b[i].y<<" :: "<<k1<<" "<<k2<<endl;
            if(k1!=k2){
                ++tot;
                fafa[tot]=tot;
                fafa[k1]=tot;
                fafa[k2]=tot;
                val[tot]=b[i].val;
                add(tot,k1);
                add(tot,k2);
            }
        }
    }
    int l[N],r[N];
    int val[N];
    int fa[N][20];
    int df;
    void dfs(int x){
    //    cout<<" xx "<<x<<endl;
        int son=0;
        r[x]=-inf;l[x]=inf;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            ++son;
            dfs(y);
            fa[y][0]=x;
            r[x]=max(r[x],r[y]);
            l[x]=min(l[x],l[y]);
        }
        if(!son){
            l[x]=r[x]=++df;
        }
    }
    void pre(){
        dfs(tot);
        for(reg j=1;j<=19;++j){
            for(reg i=1;i<=tot;++i){
                fa[i][j]=fa[fa[i][j-1]][j-1];
            }
        }
    }
    int fin(int x,int lim,int typ){//beizeng go val
        int p=x;
        if(!typ){//go <=lim
            for(reg j=19;j>=0;--j){
                if(fa[p][j]){
                    if(val[fa[p][j]]<=lim) p=fa[p][j];
                }
            }
            return p;
        }else{//go >=lim
            for(reg j=19;j>=0;--j){
                if(fa[p][j]){
                    if(val[fa[p][j]]>=lim) p=fa[p][j];
                }
            }
            return p;
        }
    }
}kt[2];//0:min tree;1:max tree;

int num;
struct po{
    int x,y;
    bool friend operator <(po a,po b){
        return a.x<b.x;
    }
}p[N];
int ans[N];

int tot;
struct que{
    int id,x,typ,y1,y2;
    bool friend operator <(que a,que b){
        return a.x<b.x;
    }
}q[N*2];

struct binarytree{
    int f[N];
    void upda(int x){
        for(;x<=n;x+=x&(-x)) f[x]++;
    }
    int query(int x){
        int ret=0;
        for(;x;x-=x&(-x)) ret+=f[x];
        return ret;
    }
}t;
int main(){
    rd(n);rd(m);rd(Q);
    for(reg i=1;i<=m;++i){
        rd(b[i].x);rd(b[i].y);

        ++b[i].x;++b[i].y;//warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        b[i].val=max(b[i].x,b[i].y);
    }
    sort(b+1,b+m+1,cmp0);
    for(reg i=1;i<=2*n;++i){
        fafa[i]=i;
    }
    kt[0].build(0);

    kt[0].pre();
//    cout<<" after build small "<<endl;
    for(reg i=1;i<=m;++i){
        b[i].val=min(b[i].x,b[i].y);
    }
    sort(b+1,b+m+1,cmp1);
    for(reg i=1;i<=2*n;++i){
        fafa[i]=i;
    }
    kt[1].build(1);
    kt[1].pre();

    int st,nd,L,R;
    for(reg i=1;i<=Q;++i){
        rd(st);rd(nd);rd(L);rd(R);
        ++L;++R;
        ++st;++nd;//warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        int ptr=kt[1].fin(st,L,1);
        q[++tot].id=i;
        q[tot].y1=kt[1].l[ptr];
        q[tot].y2=kt[1].r[ptr];

        q[++tot].id=i;
        q[tot].y1=kt[1].l[ptr];
        q[tot].y2=kt[1].r[ptr];

        ptr=kt[0].fin(nd,R,0);
        q[tot-1].x=kt[0].l[ptr]-1;
        q[tot].x=kt[0].r[ptr];

        q[tot-1].typ=-1;
        q[tot].typ=1;
    }
    sort(q+1,q+tot+1);

    for(reg i=1;i<=n;++i){
        p[i].x=kt[0].l[i];
        p[i].y=kt[1].l[i];
    }
    sort(p+1,p+n+1);

    int ptp=1,ptq=1;
    for(reg i=1;i<=n;++i){
        while(ptp<=n&&p[ptp].x<i) ++ptp;
        if(p[ptp].x==i){
            while(ptp<=n&&p[ptp].x==i){
                t.upda(p[ptp].y);
                ++ptp;
            }
        }

        while(ptq<=tot&&q[ptq].x<i) ++ptq;
        if(q[ptq].x==i){
            while(ptq<=tot&&q[ptq].x==i){
                ans[q[ptq].id]+=q[ptq].typ*(t.query(q[ptq].y2)-t.query(q[ptq].y1-1));
                ++ptq;
            }
        }
    }

    for(reg i=1;i<=Q;++i){
        puts(ans[i]?"1":"0");
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/10 15:50:00
*/

总结:
kruskal重构树,就是考虑在经过边权在一定范围内到达的区域的点的情况

这里就是简单查询连通性

两个重构树判交的“二维数点”问题的转化很巧妙!

原文地址:https://www.cnblogs.com/Miracevin/p/10359586.html

时间: 2024-10-07 16:07:02

[IOI2018] werewolf 狼人的相关文章

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

[IOI2018] werewolf 狼人 LG传送门 kruskal重构树好题. 日常安利博客文章 这题需要搞两棵重构树出来,这两棵重构树和我们平时见过的重构树有点不同(据说叫做点权重构树?),根据经过我们简化的建树方法,这两棵树不再是二叉树,但是仍具有kruskal重构树的优秀性质,建议结合后面的描述理解. 看这题需要首先我们从\(S\)走到\(T\)转化为分别从\(S\)和\(T\)出发寻找能共同到达的点,需要快速求出从某个点出发经过点权不大(小)于\(r\)(\(l\))的点,考虑kru

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

题目链接: IOI2018werewolf 题目中编号都是从0开始,太不舒服了,我们按编号从1开始讲QAQ. 题目大意就是询问每次从一个点开始走只能走编号在[l,n]中的点,在任意点变成狼,之后只能走[0,r]中的点,是否能到达另一个点. 后一部分其实就是找有哪些点只走[0,r]中的点能到达终点,那么反过来看,就是终点只走[0,r]中的点能到达哪些点. 那么只要起点能到达的点和终点能到达的点中有交集就有解. 因为起点只能走一些编号较大的点,那么我们求出原图的最大生成树,建出kruskal重构树,

p4899 [IOI2018] werewolf 狼人

分析 我用的主席树维护qwq 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cctype> #include<cmath> #include<cstdlib> #include<ctime> #include<queue> #in

HDU 6370 Werewolf 【并查集】

任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6370 Werewolf Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 2680    Accepted Submission(s): 806 Problem Description "The Werewolves" is a p

1148 Werewolf - Simple Version (20 分)

Werewolf(狼人杀) is a game in which the players are partitioned into two parties: the werewolves and the human beings. Suppose that in a game, player #1 said: "Player #2 is a werewolf."; player #2 said: "Player #3 is a human."; player #3

PAT_A1148#Werewolf - Simple Version

Source: PAT A1148 Werewolf - Simple Version (20 分) Description: Werewolf(狼人杀) is a game in which the players are partitioned into two parties: the werewolves and the human beings. Suppose that in a game, player #1 said: "Player #2 is a werewolf."

1148 Werewolf - Simple Version (20 分)

1148 Werewolf - Simple Version (20 分) Werewolf(狼人杀) is a game in which the players are partitioned into two parties: the werewolves and the human beings. Suppose that in a game, player #1 said: "Player #2 is a werewolf."; player #2 said: "P

URAL 1242 Werewolf(DFS)

Werewolf Time limit: 1.0 secondMemory limit: 64 MB Knife. Moonlit night. Rotten stump with a short black-handled knife in it. Those who know will understand. Disaster in the village. Werewolf. There are no so many residents in the village. Many of th

狼人杀 — 水平阶级的划分

作者:来自公众号 狼人杀搞事吧 的洋洋 大家玩的时候可能经常会在局外听到有人说"某某是四阶大神-". 这次洋洋给大家介绍一下狼人杀水平的判定标准,也就是所谓的"阶级".等你了解完这些,就可以像老司机一样出去各种装逼各种吹了. 水平阶级划分介绍 0阶玩家 刚刚接触狼人杀游戏,只对角色功能有一定了解,发言比较划水或者直接过,玩神直接爆身份,常常作为闭眼玩家不知道该讲什么,当狼时比较紧张,发言漏洞比较大,基本没有悍跳预言家成功经历.    1阶玩家 了解狼人杀基本套路和逻