• [cf319E]PingPong


    分析条件,不难发现仅有以下两类边:

    1.若两区间严格相交(有公共段)且不相互包含,则两区间之间有双向边

    2.若两区间相互包含,则小区间向大区间有单向边

    对于第1类边,由于区间长度严格递增,可以通过线段树+并查集维护

    具体的,1操作时在(线段树)区间$(l,r)$上加入该点,并与在$l$和$r$处已加入的点连边

    可以使用vector暴力维护加入的点,并在连边后仅保留其中第一个点,显然可以均摊

    引理:若$a$可以到$b$,则存在一条$a$到$b$的路径,使得(至多)仅有第1步用了第2类边

    根据移动的条件,显然可以(跳过小区间)直接移动到大区间

    结合引理,即要求$a$本身或某个包含$a$的区间与$b$在同一个并查集中

    前者可以直接判定,(在前者不成立时)后者有以下结论——

    结论:其成立当且仅当$a$被$b$所在并查集中所有区间的并包含

    必要性显然,考虑充分性——

    取$b$所在并查集中包含$a$左端点向右单位长度段的区间,显然这样的区间存在

    若该区间包含$a$即得证,否则显然$a$不包含该区间,进而两者有双向边,与前者不成立矛盾

    总复杂度为$o(n\log V)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define mid (l+r>>1)
     5 pair<int,int>a[N];
     6 vector<int>v[N*100];
     7 int n,m,V,rt,p,l,r,fa[N],L[N],R[N],ls[N*100],rs[N*100];
     8 int find(int k){
     9     if (k==fa[k])return k;
    10     return fa[k]=find(fa[k]);
    11 }
    12 void merge(int x,int y){
    13     x=find(x),y=find(y);
    14     if (x==y)return;
    15     fa[y]=x,L[x]=min(L[x],L[y]),R[x]=max(R[x],R[y]);
    16 }
    17 void update(int &k,int l,int r,int x,int y,int z){
    18     if ((l>y)||(x>r))return;
    19     if (!k)k=++V;
    20     if ((x<=l)&&(r<=y)){
    21         v[k].push_back(z);
    22         return;
    23     }
    24     update(ls[k],l,mid,x,y,z);
    25     update(rs[k],mid+1,r,x,y,z);
    26 }
    27 void add(int k,int l,int r,int x,int y){
    28     if (!k)return;
    29     if (!v[k].empty()){
    30         for(int i=0;i<v[k].size();i++)merge(y,v[k][i]);
    31         v[k].resize(1);
    32     }
    33     if (l==r)return;
    34     if (x<=mid)add(ls[k],l,mid,x,y);
    35     else add(rs[k],mid+1,r,x,y);
    36 }
    37 int main(){
    38     scanf("%d",&n);
    39     for(int i=1;i<=n;i++){
    40         scanf("%d%d%d",&p,&l,&r);
    41         if (p==1){
    42             a[++m]=make_pair(l,r);
    43             fa[m]=m,L[m]=l,R[m]=r;
    44             if (r-l>=2)update(rt,-1e9,1e9,l+1,r-1,m);
    45             add(rt,-1e9,1e9,l,m),add(rt,-1e9,1e9,r,m);
    46         }
    47         if (p==2){
    48             r=find(r);
    49             if ((find(l)==r)||(L[r]<=a[l].first)&&(a[l].second<=R[r]))printf("YES\n");
    50             else printf("NO\n");
    51         }
    52     }
    53     return 0;
    54 }
    View Code
  • 相关阅读:
    2019-2020-1 20175320 《信息安全系统设计基础》第五周学习总结
    2019-2020-1 20175320 《信息安全系统设计基础》第四周学习总结
    2019-2020-1 20175320 《信息安全系统设计基础》第三周学习总结
    2018-2019-2 20175320实验五《网络编程与安全》实验报告
    20175320个人项目-趣味自然数
    MySort
    2018-2019-2 20175320实验四《Android程序设计》实验报告
    20175320 2018-2019-2 《Java程序设计》第11周学习总结
    20175320 2018-2019-2 《Java程序设计》第10周学习总结
    2018-2019-2 20175320实验三《敏捷开发与XP实践》实验报告
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/16035960.html
Copyright © 2020-2023  润新知