zoukankan      html  css  js  c++  java
  • LGOJP4381 [IOI2008]Island

    题目链接

    https://www.luogu.org/problem/P4381

    题解

    基环树直径的板子。但是dfs会爆栈...所以最后改成了bfs。还是一个很考验码力的板子。
    首先基环树的直径显然有两种情况,在不进入环的情况下在一个子树内,这直接dp求就好了。第二种是一个子树中的链+环上一段+另外一个子树中的链。按这两种情况分类讨论即可。对于这种情况,可以在先求第一种情况的同时把子树中的以子树的根为起点的最长链求出来,然后拓扑排序找出环,处理出环上的前缀和,断环成链,在上面跑一下单调队列就可以求出第二种情况下的(max)了。然后这道题里这些步骤最好都是用bfs实现,dfs可能会爆栈...各种细节也要注意好...复杂度是(O(n))的。

    #include <bits/stdc++.h>
    using namespace std;
    
    namespace io {
    char buf[1<<21], *p1 = buf, *p2 = buf;
    inline char gc() {
        if(p1 != p2) return *p1++;
        p1 = buf;
        p2 = p1 + fread(buf, 1, 1 << 21, stdin);
        return p1 == p2 ? EOF : *p1++;
    }
    #define G gc
    
    #ifndef ONLINE_JUDGE
    #undef G
    #define G getchar
    #endif
    
    template<class I>
    inline void read(I &x) {
        x = 0; I f = 1; char c = G();
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
        while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = G(); }
        x *= f;
    }
    template<class I>
    inline void write(I x) {
        if(x == 0) {putchar('0'); return;}
        I tmp = x > 0 ? x : -x;
        if(x < 0) putchar('-');
        int cnt = 0;
        while(tmp > 0) {
            buf[cnt++] = tmp % 10 + '0';
            tmp /= 10;
        }
        while(cnt > 0) putchar(buf[--cnt]);
    }
    
    #define in(x) read(x)
    #define outn(x) write(x), putchar('
    ')
    #define out(x) write(x), putchar(' ')
    
    } using namespace io;
    
    #define ll long long
    const int N = 1000100;
    
    deque<int>q;
    int n, b[N], tot, in[N];
    int head[N], cnt = 1, vis[N * 2];
    int Ctot, c[N], a[N * 2];
    struct edge {
    	int to, nxt;
    	int v;
    } e[N << 1];
    ll ans = 0, now = 0, s[N * 2], f[N * 2], d[N];
    
    void ins(int u, int v, int w) {
    	e[++cnt] = (edge) {v, head[u], w};
    	head[u] = cnt;
    }
    
    void bfs(int S, int bl) {
    	c[S] = bl;
    	q.clear(); q.push_back(S);
    	while(!q.empty()) {
    		int u = q.front(); q.pop_front();
    		c[u] = bl;
    		for(int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			if(!c[v]) q.push_back(v);
    		}
    	}
    }
    
    void topsort() {
    	q.clear();
    	for(int i = 1; i <= n; ++i) {
    		if(in[i] == 1) q.push_back(i);
    	}
    	while(!q.empty()) {
    		int u = q.front(); q.pop_front();
    		for(int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			if(in[v] > 1) {
    				d[c[u]] = max(d[c[u]], f[u] + f[v] + e[i].v);
    				f[v] = max(f[v], f[u] + e[i].v);
    				--in[v]; if(in[v] == 1) q.push_back(v);
    			}
    		}
    	}
    }
    
    void dp(int S, int vc) {
    	int tot = 0, u = S;
    	a[++tot] = u;
    	while(1) {
    		bool flag = 0;
    		in[u] = 1;
    		for(int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			if(in[v] > 1) {a[++tot] = v; s[tot] = s[tot - 1] + e[i].v; u = v; flag = 1; break;}
    		}
    		if(!flag) break;
    	}
    	if(tot == 2) {
    		int val = 0;
    		for(int i = head[S]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			if(v == a[2]) val = max(val, e[i].v);
    		}
    		d[vc] = max(d[vc], f[a[1]] + f[a[2]] + val);
    		return;
    	}
    	for(int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if(v == S) {a[++tot] = S; s[tot] = s[tot - 1] + e[i].v; break;}
    	}
    	for(int i = tot + 1; i <= (tot - 1) * 2; ++i) {
    		a[i] = a[i - tot + 1];
    		s[i] = s[i - 1] + s[i - tot + 1] - s[i - tot]; 
    	}
    	q.clear(); q.push_back(1);
    	ll sum = 0;
    	for(int i = 2; i <= (tot - 1) * 2; ++i) {
    		while(!q.empty() && i - q.front() + 1 > (tot - 1)) q.pop_front();
    		sum = max(sum, f[a[q.front()]] + f[a[i]] + s[i] - s[q.front()]);
    		while(!q.empty() && f[a[i]] - s[i] > f[a[q.back()]] - s[q.back()]) q.pop_back();
    		q.push_back(i); 
    	}
    	d[vc] = max(d[vc], sum);
    }
    
    int main() {
    	read(n);
    	for(int x, i = 1; i <= n; ++i) {
    		ll w; read(x); read(w);
    		ins(i, x, w), ins(x, i, w);
    		in[i]++; in[x]++;
    	}
    	for(int i = 1; i <= n; ++i) {
    		if(!c[i]) bfs(i, ++Ctot); 
    	}
    	topsort();
    	for(int i = 1; i <= n; ++i) {
    		if(!vis[c[i]] && in[i] > 1) {
    			vis[c[i]] = 1;
    			dp(i, c[i]);
    			ans += d[c[i]];
    		}
    	}
    	outn(ans);
    }
    
  • 相关阅读:
    全局与本地游标演示.sql
    二进制文件存取示例(TSQL)
    QML与c++交互学习笔记(八) qt c++直接调用QML中的函数, 直接设置属性
    Android 和 Chrome OS 融合的可能性
    Poang,基于Node.js的自动化测试范例
    ADO.NET 4.5中的异步与流特性
    Windows 8 应用前瞻
    Robot Framework作者建议如何选择自动化测试框架
    ROLLUP实现的分级汇总示例(定义各汇总列标题)
    备份指定表到另一数据库.sql
  • 原文地址:https://www.cnblogs.com/henry-1202/p/11282209.html
Copyright © 2011-2022 走看看