zoukankan      html  css  js  c++  java
  • Gym 101480G BZOJ 4432 [CERC2015]Greenhouse Growth (链表)

    题目链接

    (Gym) https://codeforces.com/gym/101480/standings
    (BZOJ) 大人,时代变了。

    题解

    很神仙的题。
    显然如果相邻两个数相等那么它们永远会相等,于是可以把相等的连续段缩到一起。
    用链表维护所有的连续段,并对每个连续段维护以下信息:
    (l),(r): 该连续段在原序列中对应的范围。
    (h),(t): 该连续段上次更新的时间为 (t)、在那时的高度为 (h).
    (fa),(fb): 发生 A/B 类操作时该连续段是否会增高。
    那么在不发生合并操作的前提下,时刻 (t_1) 该连续段的高度为 (h+fa(sa_{t_1}-sa_t)+fb(sb_{t_1}-sb_t)),其中 (sa_i,sb_i) 分别表示前 (i) 个时刻 A 和 B 操作的个数。

    对每一对相邻连续段,维护:
    (ga),(gb): 发生 A/B 类操作时,两个连续段高度的差距是否会缩小(缩小的幅度只能是 (0)(1))。
    并由此计算这两个连续段发生合并的时间,到时间的时候进行合并。
    每次合并时,先计算新连续段的相关数值,然后检验新连通块相邻的两个连通块,计算合并时间,挂到对应的时间上。

    时间复杂度 (O(n+m)).

    代码

    #include<bits/stdc++.h>
    #define llong long long
    #define mkpr make_pair
    #define x first
    #define y second
    #define iter iterator
    #define riter reverse_iterator
    #define y1 Lorem_ipsum_
    #define tm dolor_sit_amet_
    #define pii pair<int,int>
    using namespace std;
    
    inline int read()
    {
    	int x = 0,f = 1; char ch = getchar();
    	for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
    	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
    	return x*f;
    }
    
    const int mxN = 3e5;
    int n,q,tot,t;
    int h[mxN+3];
    char opt[mxN+3];
    int sa[mxN+3],sb[mxN+3],ta[mxN+3],tb[mxN+3];
    struct Node
    {
    	int prv,nxt,l,r,h,t,fa,fb,ga,gb; bool del;
    } li[mxN*2+3];
    queue<pii> que[mxN+3];
    
    void calch(int u)
    {
    	if(!u) return;
    	li[u].h += (sa[t]-sa[li[u].t])*li[u].fa+(sb[t]-sb[li[u].t])*li[u].fb;
    	li[u].t = t;
    }
    void calcg(int u)
    {
    	if(li[u].del||li[li[u].prv].del) return;
    	calch(u); calch(li[u].prv);
    	if(li[u].h==li[li[u].prv].h) {que[t].push(mkpr(u,li[u].prv)); return;}
    	li[u].ga = li[u].fa^li[li[u].prv].fa; li[u].gb = li[u].fb^li[li[u].prv].fb;
    	int x = abs(li[u].h-li[li[u].prv].h);
    	if(li[u].ga&&!li[u].gb) {if(sa[t]+x<=q) {que[ta[sa[t]+x]].push(mkpr(u,li[u].prv));}}
    	else if(!li[u].ga&&li[u].gb) {if(sb[t]+x<=q) {que[tb[sb[t]+x]].push(mkpr(u,li[u].prv));}}
    	else if(li[u].ga&&li[u].gb) {if(t+x<=q) {que[t+x].push(mkpr(u,li[u].prv));}}
    }
    void merge(int u,int v)
    {
    	if(li[u].del||li[v].del) return;
    	tot++; li[tot].prv = li[li[u].prv].prv,li[tot].nxt = li[u].nxt,li[li[tot].prv].nxt = tot,li[li[tot].nxt].prv = tot; li[li[u].prv].del = li[u].del = true;
    	calch(u); li[tot].h = li[u].h; li[tot].t = t; li[tot].l = li[li[u].prv].l,li[tot].r = li[u].r;
    	calch(li[tot].prv); calch(li[tot].nxt); li[tot].fa = (li[li[tot].prv].h>li[tot].h); li[tot].fb = (li[li[tot].nxt].h>li[tot].h);
    	if(li[tot].prv) {calcg(tot);} if(li[tot].nxt) {calcg(li[tot].nxt);}
    }
    
    int main()
    {
    	n = read(),q = read();
    	for(int i=1; i<=n; i++) h[i] = read();
    	scanf("%s",opt+1);
    	for(int i=1; i<=q; i++) {sa[i] = sa[i-1],sb[i] = sb[i-1]; if(opt[i]=='A') {sa[i]++; ta[sa[i]] = i;} else {sb[i]++; tb[sb[i]] = i;}}
    	for(int l=1; l<=n; l++)
    	{
    		int r = l; while(r<n&&h[r+1]==h[l]) {r++;}
    		tot++; li[tot-1].nxt = tot,li[tot].prv = tot-1;
    		li[tot].l = l,li[tot].r = r,li[tot].h = h[l],li[tot].t = 0; li[tot].fa = (h[l-1]>h[l]); li[tot].fb = (h[r+1]>h[r]);
    		l = r;
    	}
    	for(int i=li[li[0].nxt].nxt; i; i=li[i].nxt) {calcg(i);}
    	for(int i=1; i<=q; i++)
    	{
    		t = i;
    		while(!que[i].empty())
    		{
    			pii u = que[i].front(); que[i].pop();
    			merge(u.x,u.y);
    		}
    	}
    	for(int i=li[0].nxt; i; i=li[i].nxt)
    	{
    		calch(i);
    		for(int j=li[i].l; j<=li[i].r; j++) {printf("%d ",li[i].h);}
    	}
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    ARP攻击原理与解决
    如何查看数据库各种表oracle
    MyEclipse 8.0注册码
    oracle数据库导入导出
    输出设备已满或不可用, 归档程序无法归档重做日志[oracle解决方法]
    句柄以及对象的比较java
    shutdown immediate 后无法启动实例问题解决
    马云经典语录
    海量数据处理分析_BI
    数据库迁移方案
  • 原文地址:https://www.cnblogs.com/suncongbo/p/14293489.html
Copyright © 2011-2022 走看看