zoukankan      html  css  js  c++  java
  • CF587D Duff in Mafia 题解

    安利(:) 杂题选做

    题目链接-Codeforces

    首先忽略边权(,)考虑求一组可行的方案(.)可以使用(2-SAT)实现(,)建图需要前后缀优化(.)

    加上边权的限制就是加一个二分(.)

    强制让一个东西不能选就是加一条 ((x,1)->(x,0)) 的边(.)

    (O(mlogm),)实现的时候注意节省空间(.)

    我的代码是(|V|leq 7m,) (|E| leq 17m)


    关于前后缀优化(:)

    考虑我把原图中的点都拿出来并排成一排(p_1,p_2,..,p_m.)

    然后我需要快速实现若干次一个点(u)往这一排点连边或者往这一排点中除了一个点的其他点连边(.)

    那么(,)可以建出辅助点(pre_i)(suf_i,)分别表示连向(p_{1..i})和连向(p_{i..m})的点(.)

    然后就可以连一个前缀(,)连一个后缀(,)就解决问题了(.)

    一排点往点(u)连边的过程类似(.)

    这个优化建图是线性的(.)


    代码(:)

    #include <bits/stdc++.h>
    using namespace std;
    template <typename T> void read(T &x){
    	x = 0; int f = 1; char ch = getchar();
    	while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    	while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
    	x *= f;
    }
    inline void write(int x){if (x > 9) write(x/10); putchar(x%10+'0'); }
    
    const int N = 50005,M = 50005,V = N * 7,E = M * 17;
    
    int cntv;
    int He[V],Ne[E],To[E],_k;
    inline void init(){ for (int i = 1; i <= cntv; ++i) He[i] = 0; _k = 0; }
    inline void add(int x,int y){ ++_k; To[_k] = y,Ne[_k] = He[x],He[x] = _k; }
    
    int Time,dfn[V],low[V],vis[V],stk[V],top,scc[V],scc_cnt;
    inline void dfs(int x){
    	dfn[x] = low[x] = ++Time; stk[++top] = x; vis[x] = 1;
    	for (int y,p = He[x]; p ; p = Ne[p]){
    		y = To[p];
    		if (!dfn[y]) dfs(y),low[x] = min(low[x],low[y]);
    		else if (vis[y]) low[x] = min(low[x],dfn[y]);
    	}
    	if (low[x] == dfn[x]){
    		scc[x] = ++scc_cnt; vis[x] = 0;
    		while (stk[top] ^ x) scc[stk[top]] = scc[x],vis[stk[top]] = 0,--top;
    		--top;
    	}
    }
    inline void tarjan(){
    	int i;
    	Time = 0,top = 0,scc_cnt = 0;
    	for (i = 1; i <= cntv; ++i) dfn[i] = low[i] = vis[i] = scc[i] = stk[i] = 0;
    	for (i = 1; i <= cntv; ++i) if (!dfn[i]) dfs(i);
    }
    int n,m,ex[M],ey[M],ec[M],et[M];
    
    int eex[E],eey[E],le;
    
    vector<int>G[N];
    inline void build(int w){
    	static int p[N],lenp,i,q[N],x,y;
    	lenp = G[w].size();
    	for (i = 1; i <= lenp; ++i) p[i] = G[w][i-1];
    	for (i = 2; i <= lenp; ++i){ q[i] = ++cntv; ++le; eex[le] = q[i],eey[le] = p[i]; }
    	for (i = 2; i < lenp; ++i){ ++le; eex[le] = q[i],eey[le] = q[i+1]; }
    	for (i = 1; i < lenp; ++i){ ++le; eex[le] = p[i]+m,eey[le] = q[i+1]; }
    	for (i = 1; i < lenp; ++i){ q[i] = ++cntv; ++le; eex[le] = q[i],eey[le] = p[i]; }
    	for (i = 2; i < lenp; ++i){ ++le; eex[le] = q[i],eey[le] = q[i-1]; }
    	for (i = 2; i <= lenp; ++i){ ++le; eex[le] = p[i]+m,eey[le] = q[i-1]; }
    }
    inline void work(){
    	int i,x,y;
    	map<pair<int,int> ,int>M; M.clear();
    	cntv = m<<1;
    	for (i = 1; i <= m; ++i){
    		G[ex[i]].push_back(i),G[ey[i]].push_back(i);
    		if (M.count(make_pair(ec[i],ex[i]))){
    			x = M[make_pair(ec[i],ex[i])],y = i;
    			++le; eex[le] = x,eey[le] = y+m;
    			++le; eex[le] = x+m,eey[le] = y;
    			++le; eex[le] = y,eey[le] = x+m;
    			++le; eex[le] = y+m,eey[le] = x; 
    		}
    		else M[make_pair(ec[i],ex[i])] = i;
    		
    		if (M.count(make_pair(ec[i],ey[i]))){
    			x = M[make_pair(ec[i],ey[i])],y = i;
    			++le; eex[le] = x,eey[le] = y+m;
    			++le; eex[le] = x+m,eey[le] = y;
    			++le; eex[le] = y,eey[le] = x+m;
    			++le; eex[le] = y+m,eey[le] = x; 
    		}
    		else M[make_pair(ec[i],ey[i])] = i;
    	}
    	for (i = 1; i <= n; ++i) if (G[i].size() > 1) build(i);
    }
    
    inline bool check(int v,int tp){
    	int i;
    	init();
    	for (i = 1; i <= le; ++i) add(eex[i],eey[i]);
    	for (i = 1; i <= m; ++i) if (et[i] > v) add(i+m,i);
    	tarjan();
    	for (i = 1; i <= m; ++i) if (scc[i] == scc[i+m]) return 0;
    	if (!tp) return 1;
    	int cnt = 0;
    	for (i = 1; i <= m; ++i) cnt += scc[i+m] < scc[i];
    	write(v),putchar(' '),write(cnt),putchar('
    ');
    	for (i = 1; i <= m; ++i) if (scc[i+m] < scc[i]) write(i),putchar((--cnt)?' ':'
    ');
    	return 1;
    }
    
    namespace sub0{
    	int v[M],lv,cnt[N]; vector<int>G[N];
    	inline bool chk(){
    		int i,j,id,x,y;
    		for (i = 1; i <= m; ++i) v[i] = ec[i]; sort(v+1,v+m+1),lv = unique(v+1,v+m+1)-v-1;
    		for (i = 1; i <= m; ++i) ec[i] = lower_bound(v+1,v+lv+1,ec[i])-v,G[ec[i]].push_back(i);
    		for (i = 1; i <= m; ++i) if (G[i].size()){
    			for (j = 0; j < G[i].size(); ++j){
    				id = G[i][j],x = ex[id],y = ey[id],++cnt[x],++cnt[y];
    				if (cnt[x] > 2) return 0; if (cnt[y] > 2) return 0;
    			}
    			for (j = 0; j < G[i].size(); ++j) id = G[i][j],x = ex[id],y = ey[id],--cnt[x],--cnt[y];
    		}
    		return 1;
    	}
    }
    
    int main(){
    	int i;
    	read(n),read(m);
    	for (i = 1; i <= m; ++i) read(ex[i]),read(ey[i]),read(ec[i]),read(et[i]);
    	if (!sub0::chk()){ puts("No"); return 0; }
    	work();
    	int L = 0,R = 1e9 + 7,Mid,Ans = R;
    	while (L <= R){ Mid = L+R>>1; if (check(Mid,0)) Ans = Mid,R = Mid - 1; else L = Mid + 1; }
    	if (Ans > 1000000000) puts("No"); else puts("Yes"),check(Ans,1);
    	return 0;
    }
    
  • 相关阅读:
    VS2015快捷键
    layui radio 监听
    jsvascript === 和==的区别
    bootstrap table checkbox 根据值选中、禁用等
    table 中 display为 block 时 tbody 失去宽度
    打包成Zip
    Server.MapPath()用法
    JS比较当前时间是否在指定时间段内
    从多张表获取数据,重组DataTable,根据重组路径,打包下载文件。
    checkbox 根据值选中
  • 原文地址:https://www.cnblogs.com/s-r-f/p/13584308.html
Copyright © 2011-2022 走看看