zoukankan      html  css  js  c++  java
  • Codeforces 1132G(关系转化树+dfn+线段树)

    要点

    • 显然要滑动修改维护。
    • 像通常的数列next关系一样建边(单调栈预处理),因为贪心所以是树,然后发现增删只会影响区间内的子(or父,看你连边方向行事)节点,于是使用dfs序建线段树。
    • 为了正确地修改,会发现必须得用大数向小数连边。一是根据题意,一个大数会有好几个小数儿子但小数只会贪心选一个父亲;二是每当增加一个大数时,对每个子孙都会有一个贡献,正好我们用size数组搞定左右边界。
    • 某些子孙已经被滑动窗口移除了,加进一个大数又给它加了1,不会影响吗?不影响答案,因为移除以后它是0,只会有一个父亲出现才会增加它为1,并不影响最终答案。
    const int maxn = 1e6 + 5;
    int n, k, a[maxn], dfn[maxn], Time, size[maxn];
    vector<int> adj[maxn];
    
    class SegmentTree {
    public:
    	#define ls(p)	p << 1
    	#define rs(p)	p << 1 | 1
    	struct Node {
    		int l, r, maxx, tag;
    	}t[maxn << 2];
    
    	void Push_up(int p) {
    		t[p].maxx = max(t[ls(p)].maxx, t[rs(p)].maxx);
    	}
    
    	void Push_down(int p) {
    		if (t[p].tag) {
    			t[ls(p)].maxx += t[p].tag, t[rs(p)].maxx += t[p].tag;
    			t[ls(p)].tag += t[p].tag, t[rs(p)].tag += t[p].tag;
    			t[p].tag = 0;
    		}
    	}
    
    	void Build(int l, int r, int p) {
    		t[p].l = l, t[p].r = r;
    		if (l == r)	return;
    		int mid = (l + r) >> 1;
    		Build(l, mid, ls(p));
    		Build(mid + 1, r, rs(p));
    	}
    
    	void Modify(int l, int r, int p, int k) {
    		if (l <= t[p].l && t[p].r <= r) {
    			t[p].maxx += k, t[p].tag += k;
    			return;
    		}
    		Push_down(p);
    		int mid = (t[p].l + t[p].r) >> 1;
    		if (l <= mid)	Modify(l, r, ls(p), k);
    		if (mid < r)	Modify(l, r, rs(p), k);
    		Push_up(p);
    	}
    }T;
    
    void dfs(int fa) {
    	dfn[fa] = ++Time;
    	size[fa] = 1;
    	for (auto i : adj[fa]) {
    		dfs(i);
    		size[fa] += size[i];
    	}
    }
    
    void Pre() {
    	stack<int> st;
    	irep(i, n, 1) {
    		while (!st.empty() && a[st.top()] <= a[i])	st.pop();
    		int fa = st.empty() ? n + 1 : st.top();
    		adj[fa].push_back(i);
    		st.push(i);
    	}
    	dfs(n + 1);
    }
    
    void Solve() {
    	T.Build(1, n + 1, 1);
    	rep(i, 1, k - 1)	T.Modify(dfn[i], dfn[i] + size[i] - 1, 1, 1);
    	for (int i = 1; i + k - 1 <= n; i++) {
    		T.Modify(dfn[i + k - 1], dfn[i + k - 1] + size[i + k - 1] - 1, 1, 1);
    		printf("%d ", T.t[1].maxx);
    		T.Modify(dfn[i], dfn[i] + size[i] - 1, 1, -1);
    	}
    }
    
    int main() {
    	read(n), read(k);
    	rep(i, 1, n)	read(a[i]);
    	Pre();
    	Solve();
    	return 0;
    }
    
  • 相关阅读:
    c文件操作库
    双链常用操作2
    双向链表常用操作
    c队列操作
    c日期格式化操作之date
    单链常用操作类
    c字符串常用操作
    双向链表通用类
    c栈操作
    poj2509
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10693557.html
Copyright © 2011-2022 走看看