• CF1023G Pisces【数据结构优化 dp】


    这仍然是最小链覆盖问题,转化为求最大反链。

    然后考虑用上树的性质进行优化:条件集合 (S) 构成反链 (Leftrightarrow) 选定一个没有条件的节点 (rt) 做根,对 (rt) 的所有儿子 (x) 的子树 ( ext{sub}(x))(S) 的交构成反链,且存在时刻 (T) 满足 (forall(v,d)in S)(d+ ext{dep}_v>T)(d- ext{dep}_v<T)

    注意 (T) 不一定是整数,但是若将所有边权以及 (d) 变为两倍,(T) 就是整数了。

    于是就可以 dp 了,设 (f_{u,t}) 表示考虑 (u) 的子树(除了 (u)),(T=t) 的时候的最大反链。

    考虑将 (f_u) 合并进父亲:设贡献为 (f'_u)(u) 与父亲的连边长度为 (l),若 (u) 没有元素,那么就是 (f_{u,i}'=max_{j=i-l}^{i+l}f_{u,j}),称这个操作为向上走 (l)

    那如果有元素怎么办,设条件 ((u,d)) 上有 (x),考虑到贡献时刻为 ([d-l+1,d+l-1]),应当是向上走 (1) 步,然后 (f_{u,d}':=max(f_{u,d}',f_{u,d}+x)),然后向上走 (l-1) 步。

    dp 数组很大存不下,但都是一大段相同的,所以考虑维护差分数组。

    向上走 (l) 步这个操作就是正数向左 (l) 步,负数向右 (l) 步,相遇的正负抵消。

    所以可以用 map 存差分数组,用懒标记 (add) 表示向上走了多少步,用 priority_queue 维护相邻的负数和正数,按距离排序,走 (l) 步的时候就把距离 (leq 2(add+l)) 的合并,然后 (add:=add+l)

    合并的时候就把差分数组加起来,所以启发式合并就可以了。

    时间复杂度 (O(n+klog^2k))

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define PB emplace_back
    using namespace std;
    typedef pair<int, int> pii;
    const int N = 100003;
    int rd(){
    	int ch = getchar(), x = 0;
    	for(;ch < '0' || ch > '9';ch = getchar());
    	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
    	return x;
    }
    template<typename T>
    bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    int n;
    vector<pii> G[N], V[N];
    struct DS {
    	map<int, int> ps, ng; int tag;
    	priority_queue<pii, vector<pii>, greater<pii> > pq;
    	void reb(int x, bool op){
    		if(op){ // positive
    			auto it = ng.upper_bound(x-(tag<<1));
    			if(it == ng.begin()) return; --it;
    			pq.emplace(x-it->fi, x);
    //			printf("pq <- %d, %d
    ", it->fi, x);
    		} else { // negative
    			auto it = ps.lower_bound(x+(tag<<1));
    			if(it == ps.end()) return;
    			pq.emplace(it->fi-x, it->fi);
    //			printf("pq <- %d, %d
    ", x, it->fi);
    		}
    	}
    	void ins(int x, int val){
    		if(val > 0){
    			ps[x+tag] += val;
    			reb(x+tag, true);
    		} else {
    			ng[x-tag] += val;
    			reb(x-tag, false);
    		}
    	}
    	int get() const {
    		int res = 0, now = 0;
    		auto i = ps.begin(), j = ng.begin();
    		while(i != ps.end() && j != ng.end()){
    			if(i->fi-j->fi>=(tag<<1)){
    				now += j->se; ++j;
    			} else {
    				now += i->se; ++i;
    			} chmax(res, now);
    		} return res;
    	}
    	void work(int l){
    		while(!pq.empty()){
    			pii _ = pq.top();
    			if(_.fi > (tag+l<<1)) break;
    			pq.pop();
    			int x = _.se, y = x-_.fi;
    			auto i = ps.find(x), j = ng.find(y);
    			if(i == ps.end() || j == ng.end()) continue;
    			if(i->se + j->se < 0){
    				j->se += i->se; ps.erase(i); reb(j->fi, false);
    			} else {
    //			printf("x = %d, y = %d
    ", x, y);
    				i->se += j->se; ng.erase(j); reb(i->fi, true);
    //				printf("ng.erase(j)
    ");
    			}
    		} tag += l;
    	}
    	size_t size() const {return ps.size()+ng.size();}
    	int qry(int p) const {
    		auto i = ps.find(p+tag), j = ng.find(p-tag);
    		return (i==ps.end()?0:i->se)+(j==ng.end()?0:j->se);
    	}
    	void operator += (const DS &o){
    		for(pii i : o.ps) ins(i.fi-o.tag, i.se);
    		for(pii i : o.ng) ins(i.fi+o.tag, i.se);
    	}
    } S[N];
    void dfs(int x, int fa){
    	for(pii _ : G[x]) if(_.fi != fa){
    		int v = _.fi, len = _.se;
    		dfs(v, x);
    		for(pii &i : V[v]) i.se -= max(0, max(-S[v].qry(i.fi), S[v].qry(i.fi+1)));
    		S[v].work(1);
    		for(pii i : V[v]) if(i.se > 0){
    			S[v].ins(i.fi, i.se);
    			S[v].ins(i.fi+1, -i.se);
    		}
    		S[v].work(len-1);
    		if(S[x].size() < S[v].size()) swap(S[x], S[v]);
    		S[x] += S[v];
    	}
    }
    int main(){
    	n = rd();
    	for(int i = 1;i < n;++ i){
    		int u = rd(), v = rd(), l = rd()<<1;
    		G[u].PB(v, l); G[v].PB(u, l);
    	}
    	int m = rd(); G[0].PB(1, 2);
    	while(m --){
    		int d = rd()<<1, f = rd(), p = rd();
    		V[p].PB(d, f);
    	} dfs(0, 0);
    	printf("%d
    ", S[0].get());
    }
    
  • 相关阅读:
    PHP中的闭包详解
    PHPDoc 学习记录
    php中注释有关内容
    命名空间 转
    php命名空间学习笔记。
    php命名空间详解
    命名空间
    php作用域限定符
    nginx负载均衡
    naginx安装入门
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/14907466.html
Copyright © 2020-2023  润新知