xjoi 省选训练23_B

这场我tm 爆零了!!!!! 

发现这题是一个基环树森林 拓扑排序去掉 不在环上的节点以后 只剩下一个环

那么这题就成了 环上的覆盖问题 

算法1: 倍增 嗯。。。我好想不会写

算法2: 选取k个点 每一次 走k个点 那么每一次 就只会走 [n/k]步 可以先预处理出每一步 走了以后 你能走到哪里

    那么对于每一个环 我们只需要 进行O(n) 就可以做到 这个环的最小覆盖 可惜我比较NAIVE 没有写这个东西

算法3: 真不好意思 这个是最烙算法 我还坑害了我边上的z1j1n1大爷 捂脸熊  

    发现以前做过的一道题叫做——出纳员的雇佣 由于以前比较naive 写的是枚举答案 如果写成二分 并且 用dfs判判负环

(要打时间戳) 就可以O(玄学) (据信 复杂度是(O(logN*N))) 加个O2 就可以过了爆零这题辣!!

  1 #pragma GCC optimize (2)
  2 #include <bits/stdc++.h>
  3 #define N 500010
  4 #define inf 0x7fffffff
  5 using namespace std;
  6   
  7 inline int read()
  8 {
  9     int x=0,f=1;char ch=getchar();
 10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 11     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 12     return x*f;
 13 }
 14 int n,k,ee,st[N],d[N],sign[N],ans,fa[N];
 15 int ned[N],emp[N];
 16 struct cirle_solve_the_problem
 17 {
 18     struct edge{
 19         int v,w,next;
 20     }vs[N*6];
 21     int st[N],ee,k,dist[N],cnt[N],vis[N],len,dis[N],flag;
 22     queue <int> q;
 23     void addedge(int u,int v,int w)
 24     {
 25         vs[++ee].v=v;vs[ee].w=w;
 26         vs[ee].next=st[u];st[u]=ee;
 27     }
 28     void dfs(int rt,int pr){
 29         vis[rt]=pr;
 30         for(int i=st[rt];i;i=vs[i].next){
 31             if(dis[vs[i].v]>dis[rt]+vs[i].w){
 32                 if(vis[vs[i].v]==pr){flag=1;return;}
 33                 dis[vs[i].v]=dis[rt]+vs[i].w;
 34                 dfs(vs[i].v,pr);if(flag) return ;
 35             }
 36         }vis[rt]=0;
 37     }
 38     bool check(int pr){
 39         flag=0;
 40         for(int i=0;i<=len;i++) dis[i]=10000000;
 41         for(int i=0;i<=len;i++) {dfs(i,pr);
 42             if(flag) return 1;}
 43         return 0;
 44     }
 45     void graph(int lim){
 46         ee=0;for(int i=0;i<=len;i++) st[i]=0;
 47         for(int i=1;i<=len;i++){
 48             addedge(i,i-1,0);
 49             addedge(i-1,i,emp[i]);
 50         }
 51         for(int i=k;i<=len;i++)
 52             addedge(i,i-k,-ned[i]);
 53         for(int i=1;i<k;i++)
 54             addedge(i,i+len-k,lim-ned[i]);
 55         addedge(len,0,-lim);
 56     }
 57     bool spfa(int lim,int pr){
 58         if(n>5000)return 1;
 59         queue <int> q;
 60         for(int i=0;i<=len;i++) dist[i]=inf;
 61         q.push(len);dist[len]=0;vis[len]=pr;
 62         while(!q.empty()){
 63             int lx=q.front();q.pop();
 64             for(int i=st[lx];i;i=vs[i].next)
 65                 if(dist[lx]+vs[i].w<dist[vs[i].v]){
 66                     dist[vs[i].v]=dist[lx]+vs[i].w;
 67                     if(vis[vs[i].v]!=pr)
 68                         q.push(vs[i].v),vis[vs[i].v]=pr;            
 69                 }
 70             vis[lx]=0;
 71         }
 72         if(dist[0]>=-lim) return 1;return 0;
 73     }
 74     int cirle_solve(int a,int b)
 75     { 
 76         k=a;len=b;
 77         int r=len/k+1,nn=0;
 78         for(int i=1;i<=len;i++) nn+=(ned[i]>0);
 79         if(k>=len) return (nn)? 1:0;
 80         if(!nn) return 0;  int l=0,ans=0x7fffffff;
 81         while(l<=r)
 82         {
 83             int mid=(l+r)>>1;
 84             graph(mid);
 85             if(!check(mid)&&spfa(mid,mid)) r=mid-1,ans=min(ans,mid);
 86             else l=mid+1;
 87         }
 88         return ans;
 89     }
 90 }T;
 91 void pre()
 92 {
 93     queue <int> q; while(!q.empty()) q.pop();
 94     for(int i=1;i<=n;i++) if(!d[i]) q.push(i);
 95     sign[1]=k+1;
 96     while(!q.empty())
 97     {
 98         int lx=q.front(); q.pop();
 99         if(!sign[lx]) sign[lx]=k,ans++;
100         int now=lx;d[fa[now]]--;
101         if(!d[fa[now]]) q.push(fa[now]);
102         sign[fa[now]]=max(sign[now]-1,sign[fa[now]]);
103     }
104 }
105 void deal()
106 {
107     for(int i=1;i<=n;i++)
108     {
109         if(d[i])
110         {
111             int now=i; d[now]=0; int len=1;
112             if(!sign[now]) ned[len]=1;
113             else ned[len]=0,
114                 sign[fa[now]]=max(sign[now]-1,sign[fa[now]]);  emp[len]=1; len++;
115             for(int j=fa[now];j!=now;j=fa[j],len++)
116             {
117                 emp[len]=1; d[j]=0;
118                 if(!sign[j]) ned[len]=1;
119                 else ned[len]=0,sign[fa[j]]=max(sign[j]-1,sign[fa[j]]);
120             }
121             len=1;
122             if(!sign[now]) ned[len]=1;
123             else ned[len]=0,
124                 sign[fa[now]]=max(sign[now]-1,sign[fa[now]]);  emp[len]=1; len++;
125             for(int j=fa[now];j!=now;j=fa[j],len++)
126             {
127                 emp[len]=1; d[j]=0;
128                 if(!sign[j]) ned[len]=1;
129                 else ned[len]=0,sign[fa[j]]=max(sign[j]-1,sign[fa[j]]);
130             }
131             ans+=T.cirle_solve(k,len-1);
132         }
133     }
134       
135 }
136 int main()
137 {
138     //freopen("B_small.in","r",stdin);
139     n=read();k=read();
140     for(int i=1;i<=n;i++)
141     {
142         int a=read(),b=read();
143         fa[a]=b; d[b]++;
144     }
145     pre();
146     deal();
147     cout<<ans<<endl;
148     return 0;
149 }

不好意思 我太菜了 这份代码TLE 96 某一点 我好像过不去

 

posted @ 2017-01-23 20:26  蛤鸡  阅读(175)  评论(0编辑  收藏  举报