zoukankan      html  css  js  c++  java
  • Atcoder ABC155 F

    题目链接:ABC155 F - Perils in Parallel

    题意:

    一个国家中被放了 (N) 颗炸弹,序号为 (1)(N),第 (i) 个炸弹位于坐标 (A_i),若 (B_i=1),它目前处于激活态,反之则不处于激活态。这个炸弹系统有序号为 (1)(M)(M) 根电缆,若我们切断电缆 (j),则位于 ([L_j,R_j]) 的炸弹状态会切换,(0)->(1)(1)->(0)
    请计算是否能使所有炸弹同时处于非激活态,如果可行,输出要切断的电缆。
    (1leq Nleq 10^5)
    (1leq Aileq 10^9)(A_i) 互不相同
    (1leq Mleq 2*10^5)
    (1leq L_jleq R_jleq 10^9)

    思路:

    首先将每个区间操作差分化,切断一根电缆只会改变两个地方的异或值,我们将相邻两个元素的异或看成一个节点,把电缆切断后改变的两个点之间连边,得到一张无向图,由于选一条路径时我们只关注端点的情况(中间的点变了两次,等于没变),而且是想让异或值为1的点两两配对,可以发现环不环是不重要的。

    对所有连通块 (DFS)(随便一棵树其实都行),考虑如何配对,如果子树内异或值为1的点数量为偶数,则应该已经配好了,若为奇数,我们需要向外帮没配对的点找对象,就把现在这条边选上,如果没有配对,则边会一直连出去,直到点数为偶数,此时肯定是配上了。

    如果发现整个连通块异或值为1的点数量是奇数,则无解。

    时间复杂度 (O(NlogN)) ,瓶颈在于给坐标排序。这题算是 (ABC) 中很有难度的一题了,一开始没做出来,主要是没想到无向图可以直接转化成树。

    Code:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define per(i,b,a) for(int i=b;i>=a;i--)
    #define PII pair<int,int>
    #define mk make_pair
    #define fr first
    #define sc second
    #define N 100100
    #define M 200201
    using namespace std;
    int head[N],to[M*2],nxt[M*2];
    int cnt,id[2*M],siz[N];
    bool parity[N],vis[N];
    int loc[N],l[M],r[M],n,m;
    PII ab[N];
    vector<int> ans;
    void init(){mem(head,-1),cnt=-1;}
    void add_e(int a,int b,int k){
        nxt[++cnt]=head[a],head[a]=cnt,to[cnt]=b,id[cnt]=k;
    }
    bool cmp(PII a,PII b){return a.fr<b.fr;}
    void dfs(int x){
        siz[x]=parity[x];
        vis[x]=true;
        for(int i=head[x];~i;i=nxt[i]){
            if(vis[to[i]])continue;
            dfs(to[i]);
            if(siz[to[i]]&1)ans.push_back(id[i]);
            siz[x]+=siz[to[i]];
        }
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>m;
        rep(i,1,n){
            cin>>ab[i].fr>>ab[i].sc;
            loc[i]=ab[i].fr;
        }
        sort(ab+1,ab+n+1,cmp);
        sort(loc+1,loc+n+1);
        rep(i,1,n) parity[i]=ab[i].sc^ab[i-1].sc;
        parity[n+1]=ab[n].sc;
        init();
        rep(i,1,m){
            cin>>l[i]>>r[i];
            int L=lower_bound(loc+1,loc+n+1,l[i])-loc;
            int R=upper_bound(loc+1,loc+n+1,r[i])-loc;
            if(L==R)continue;
            add_e(L,R,i),add_e(R,L,i);
        }
        rep(i,1,n+1)if(!vis[i]){
            dfs(i);
            if(siz[i]&1){puts("-1");return 0;}
        }
        cout<<ans.size()<<endl;
        sort(ans.begin(),ans.end());
        rep(i,0,(int)ans.size()-1)cout<<ans[i]<<" ";
        cout<<endl;
        return 0;
    }
    

    想了一下如果题目的切电缆是有代价的怎么做,好像只会 (O(N^3)) 预处理点对距离然后二分图跑费用流的做法。

  • 相关阅读:
    安卓逆向5.Android Studio JNI静态注册(C++和Java互操作)
    安卓逆向二
    ASP.Net Core Web 在IIS下的发布流程
    Android Studio安装记录
    Vistual studio智能提示不显示或者显示为英文的解决办法
    (转)程序语言理论的学习对于程序员教育的作用
    普通用户ssh无密码登录设置
    (转)完全用GNU/Linux工作 by 王珢
    (转)谁是真正的程序语言专家
    java操作XML
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/14471119.html
Copyright © 2011-2022 走看看