zoukankan      html  css  js  c++  java
  • [loj6734]图上的游戏

    考虑原图是一条链的情况——

    思路:随机一个点$x$,将其所在段(边集)再划分为两段,重复此过程即可得到该链

    实现上,(从左到右)维护每一段的左端点和边集,二分找到最后一个删除后$x$到根不连通的段,那么其即是$x$所在段,再暴力枚举段中每一条边划分即可

    前者二分显然为$o(nlog n)$,后者即是一个类似于sort/treap的结构,总期望次数为$o(nlog n)$

    最终,总查询次数为$o(nlog n)$,可以通过

    考虑原图是一棵树的情况——

    思路:以0为根建树,求出一个链剖分的结果(链上存储点集、边集和链顶父亲所在的链),再利用链的做法求出链上点和边具体的顺序,最后将所有链组合即可得到该树

    实现上,根据思路分为两部分(求链剖分和求原树):

    求链剖分时,对每一条链维护边集、部分点集(仅考虑已经加入的点)和链顶父亲所在的链,并按照剖分顺序依次编号,那么加入一个点$x$,按以下方式处理——

    找到剩余边中在$x$到根路径上的边,这可以通过不断二分实现(即找到第一条满足删除后$x$到根不连通的边,直接二分不具备单调性,那么将其前缀均删除即可),接下来有两种情况:

    1.不存在这样的边,即$x$在某条链上,二分找到编号最大的链满足删除后$x$到根不连通,那么其即是$x$所在链,将$x$加入该链的点集即可

    2.存在这样的边,这些边必然是$x$到根路径上的一个前缀,即得到了一条新的链,而此时1中的二分即会求出该链链顶父亲所在的链

    (这里直接二分同样不具备单调性,将其后缀均删除即可)

    求原树时,对每一条链在其链顶的父亲所在的链中二分找到具体的父亲即可

    除了求链剖分中"不断二分/分治"外,其余均为直接二分显然为$o(nlog n)$,前者考虑每条边至多被得到一次,进而均摊总询问次数为$o(nlog n)$

    最终,总查询次数为$o(nlog n)$,可以通过

    结合上面两个做法,来考虑原问题——

    思路:求出一棵生成树,再求出所有非树边

    实现上,根据思路同样分为两部分(求生成树和非树边):

    求生成树时,可以参考树的做法,唯一不同的即在于$x$到根路径并不唯一,那么改为找到第一条满足将其以及其之前的边均删除后$x$到根不连通的边即可(这与之前的二分实现上一样)

    (可以理解为从前往后尽量删去当前边,并通过二分优化此过程)

    另外,当前的非树边默认已经被删除,下同

    求非树边时,按dfs序从后往前考虑点$x$,一条非树边以$x$为一个端点当且仅当将$x$到父亲的边删除、将这条边加入后$x$到根不连通,同样可以二分实现

    找到边后,还需要求出该边另一个端点,也即求dfs序最大的点满足将其和$x$到父亲的边删除、将这条边加入后$x$到根仍连通,同样也可以二分实现

    (这里的两个二分同样不具备单调性,将其前缀/后缀均加入/删除即可)

    重复此过程也即可得到所有非树边,询问次数的分析与之前类似

    最终,总查询次数为$o(mlog n)$,可以通过

      1 #include<bits/stdc++.h>
      2 #include"graph.h"
      3 using namespace std;
      4 #define N 605
      5 #define pii pair<int,int>
      6 int n,m,t,vis[N],fa[N],Fa[N],dfn[N];
      7 vector<int>Vis,v[N],e[N];
      8 vector<pii>ans;
      9 void clear(int p){
     10     for(int i=0;i<m;i++)Vis[i]=p;
     11 }
     12 void init_tree(){
     13     clear(0);
     14     for(int i=0;i<m;i++)
     15         if (vis[i]==1)Vis[i]=1;
     16 }
     17 int find1(int k){
     18     vector<int>v;
     19     for(int i=0;i<m;i++)
     20         if (!vis[i])v.push_back(i);
     21     clear(1);
     22     for(int i=0;i<v.size();i++)Vis[v[i]]=0;
     23     if (query(k,Vis))return -1;
     24     int l=0,r=(int)v.size()-1;
     25     while (l<r){
     26         int mid=(l+r>>1);
     27         clear(1);
     28         for(int i=0;i<=mid;i++)Vis[v[i]]=0;
     29         if (query(k,Vis))l=mid+1;
     30         else r=mid;
     31     }
     32     return v[l];
     33 }
     34 int find2(int k){
     35     init_tree();
     36     for(int i=1;i<t;i++)
     37         for(int j=0;j<e[i].size();j++)Vis[e[i][j]]=0;
     38     if (query(k,Vis))return 0;
     39     int l=1,r=t-1;
     40     while (l<r){
     41         int mid=(l+r+1>>1);
     42         init_tree();
     43         for(int i=mid;i<t;i++)
     44             for(int j=0;j<e[i].size();j++)Vis[e[i][j]]=0;
     45         if (query(k,Vis))r=mid-1;
     46         else l=mid;
     47     }
     48     return l;
     49 }
     50 int find3(int k,int x){
     51     int l=0,r=(int)e[k].size()-1;
     52     while (l<r){
     53         int mid=(l+r+1>>1);
     54         init_tree();
     55         Vis[e[k][mid]]=0;
     56         if (query(x,Vis))r=mid-1;
     57         else l=mid;
     58     }
     59     return v[k][l];
     60 }
     61 int find4(int k){
     62     vector<int>v;
     63     for(int i=0;i<m;i++)
     64         if (!vis[i])v.push_back(i);
     65     init_tree();
     66     for(int i=0;i<v.size();i++)Vis[v[i]]=1;
     67     Vis[Fa[k]]=0;
     68     if (!query(k,Vis))return -1;
     69     int l=0,r=(int)v.size()-1;
     70     while (l<r){
     71         int mid=(l+r>>1);
     72         init_tree();
     73         for(int i=0;i<=mid;i++)Vis[v[i]]=1;
     74         Vis[Fa[k]]=0;
     75         if (query(k,Vis))r=mid;
     76         else l=mid+1;
     77     }
     78     return v[l];
     79 }
     80 int find5(int k,int x){
     81     int l=1,r=n;
     82     while (l<r){
     83         int mid=(l+r+1>>1);
     84         init_tree();
     85         for(int i=mid;i<=n;i++)Vis[Fa[dfn[i]]]=0;
     86         Vis[x]=1;
     87         if (query(k,Vis))r=mid-1;
     88         else l=mid;
     89     }
     90     return dfn[l];
     91 }
     92 void calc(int k){
     93     vector<int>v0,fa[N];
     94     random_shuffle(v[k].begin()+1,v[k].end());
     95     v0.push_back(v[k][0]);
     96     for(int i=0;i<e[k].size();i++)fa[v[k][0]].push_back(e[k][i]);
     97     for(int i=1;i<v[k].size();i++){
     98         init_tree();
     99         int l=0,r=(int)v0.size()-1;
    100         while (l<r){
    101             int mid=(l+r+1>>1);
    102             init_tree();
    103             for(int j=0;j<fa[v0[mid]].size();j++)Vis[fa[v0[mid]][j]]=0;
    104             if (query(v[k][i],Vis))r=mid-1;
    105             else l=mid;
    106         }
    107         vector<int>e0;
    108         for(int j=0;j<fa[v0[l]].size();j++){
    109             init_tree();
    110             Vis[fa[v0[l]][j]]=0;
    111             if (query(v[k][i],Vis))e0.push_back(fa[v0[l]][j]);
    112             else fa[v[k][i]].push_back(fa[v0[l]][j]);
    113         }
    114         fa[v0[l]]=e0;
    115         v0.insert(v0.begin()+l,v[k][i]);
    116     }
    117     v[k]=v0,e[k].clear();
    118     for(int i=0;i<v[k].size();i++)e[k].push_back(fa[v0[i]][0]);
    119 }
    120 vector<pii> solve(int nn,int mm){
    121     srand(time(0));
    122     n=nn,m=mm;
    123     for(int i=0;i<m;i++){
    124         Vis.push_back(0);
    125         ans.push_back(make_pair(0,0));
    126     }
    127     for(int i=1;i<n;i++){
    128         t++;
    129         while (1){
    130             int x=find1(i);
    131             if (x<0)break;
    132             vis[x]=1,e[t].push_back(x);
    133         }
    134         int pos=find2(i);
    135         if (e[t].empty())t--,v[pos].push_back(i);
    136         else fa[t]=pos,v[t].push_back(i);
    137     }
    138     for(int i=1;i<=t;i++)calc(i);
    139     for(int i=1;i<=t;i++)
    140         if (fa[i])fa[i]=find3(fa[i],v[i][0]);
    141     dfn[0]=1,dfn[1]=0;
    142     for(int i=1;i<=t;i++)
    143         for(int j=0;j<v[i].size();j++){
    144             Fa[v[i][j]]=e[i][j];
    145             dfn[++dfn[0]]=v[i][j];
    146         }
    147     for(int i=1;i<=t;i++){
    148         ans[e[i][0]]=make_pair(fa[i],v[i][0]);
    149         for(int j=1;j<v[i].size();j++)ans[e[i][j]]=make_pair(v[i][j-1],v[i][j]);
    150     }
    151     for(int i=dfn[0];i>1;i--)
    152         while (1){
    153             int x=find4(dfn[i]);
    154             if (x<0)break;
    155             vis[x]=-1,ans[x]=make_pair(dfn[i],find5(dfn[i],x));
    156         }
    157     return ans;
    158 }
    View Code
  • 相关阅读:
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    mysql备份及恢复
    mysql备份及恢复
    mysql备份及恢复
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15493965.html
Copyright © 2011-2022 走看看