zoukankan      html  css  js  c++  java
  • Japan Alumni Group Summer Camp 2018 Day 2J AB Sort JZOJ 100137. 胖头鱼的排序(推性质+线段树)

    https://gmoj.net/senior/#main/show/100137

    题解:

    对于一个串(S),怎么求(f(S))

    把S结尾的一段连续B去掉。

    我们知道最后一定是变成AAA……BBB……

    考虑将'A'看做+1,’B‘看做-1,变成了一个折线图

    每次会使最低点+1,直到最低点=A的个数,那么答案显然是A的个数-最小前缀和。

    这题要求的是(f('B'+S+'A')),这样结尾就不用去B了,(f=S中'A'的个数-S的最小前缀和+1)

    每次由区间A变B、B变A操作,线段树维护即可。

    我一开始以为是区间reverse操作,所以写了平衡树。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 2e5 + 5;
    
    int n; char str[N];
    
    void Init() {
    	scanf("%d", &n);
    	scanf("%s", str + 2);
    }
    
    
    #define x0 t[x][0]
    #define x1 t[x][1]
    int rt, fa[N], t[N][2], siz[N], rev[N], dd[N];
    int z[N], s[N], f[N], g[N], c1[N], c2[N];
    
    void upd(int x) {
    	if(x) {
    		siz[x] = siz[x0] + siz[x1] + 1;
    		c1[x] = c1[x0] + c1[x1] + (z[x] == 1);
    		c2[x] = c2[x0] + c2[x1] + (z[x] == -1);
    		s[x] = s[x0] + s[x1] + z[x];
    		f[x] = min(f[x0], s[x0] + z[x] + f[x1]);
    		g[x] = min(g[x0], -s[x0] - z[x] + g[x1]);
    	}
    }
    void fan(int x) { if(x) z[x] = -z[x], s[x] = -s[x], swap(f[x], g[x]), swap(c1[x], c2[x]), rev[x] ^= 1;}
    void down(int x) { if(rev[x]) fan(x0), fan(x1), rev[x] = 0;}
    int lr(int x) { return t[fa[x]][1] == x;}
    void ro(int x) {
    	int y = fa[x], k = lr(x);
    	t[y][k] = t[x][!k]; if(t[x][!k]) fa[t[x][!k]] = y;
    	fa[x] = fa[y]; if(fa[y]) t[fa[y]][lr(y)] = x;
    	fa[y] = x; t[x][!k] = y;
    	upd(y); upd(x);
    }
    void xc(int x) {
    	for(; x; x = fa[x]) dd[++ dd[0]] = x;
    	while(dd[0]) down(dd[dd[0] --]);
    }
    void sp(int x, int y) {
    	xc(x);
    	for(; fa[x] != y; ro(x)) if(fa[fa[x]] != y)
    		ro(lr(x) == lr(fa[x]) ? fa[x] : x);
    }
    int kth(int x, int k) {
    	down(x);
    	if(siz[x0] >= k) return kth(x0, k);
    	if(siz[x0] + 1 == k) return x;
    	return kth(x1, k - siz[x0] - 1);
    }
    
    void build() {
    	fo(i, 1, n + 2)	{
    		if(i == 1 || i == n + 2) z[i] = 0; else
    			z[i] = (str[i] == 'B' ? -1 : 1);
    		if(i > 1) fa[i] = i - 1, t[i - 1][1] = i;
    	}
    	sp(n + 2, 0); rt = n + 2;
    }
    
    int Q, x, y;
    
    void Work() {
    	scanf("%d", &Q);
    	fo(ii, 1, Q) {
    		scanf("%d %d", &x, &y);
    		x += 2, y += 2;
    		int p = kth(rt, x - 1);
    		int q = kth(rt, y + 1);
    		sp(p, 0); sp(q, p);
    		int u = t[q][0];
    		fan(u);
    		sp(u, 0); rt = u;
    		pp("%d
    ", c1[u] - f[u] + 1);
    	}
    }
    
    int main() {
    	Init();
    	build();
    	Work();
    }
    
  • 相关阅读:
    bzoj1660[Usaco2006 Nov]Bad Hair Day 乱发节*
    bzoj1624[Usaco2008 Open] Clear And Present Danger 寻宝之路*
    bzoj1617[Usaco2008 Mar]River Crossing渡河问题*
    bzoj1681[Usaco2005 Mar]Checking an Alibi 不在场的证明*
    bzoj1631[Usaco2007 Feb]Cow Party*
    bzoj1854[Scoi2010]游戏
    bzoj2338[HNOI2011]数矩形
    bzoj1096[ZJOI2007]仓库建设
    继承原理、派生重用
    面向对象三大特性——继承(含派生)
  • 原文地址:https://www.cnblogs.com/coldchair/p/12362619.html
Copyright © 2011-2022 走看看