zoukankan      html  css  js  c++  java
  • [BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)

    神做法…%dalao,写的超详细 konjac的博客.
    如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码…

    CODE WITH ANNOTATION

    代码中6-6表示左括号’[’,用9-9表示右括号’]’.

    在这里插入图片描述emmmm…

    #include<bits/stdc++.h>
    using namespace std;
    char cb[1<<15],*cs=cb,*ct=cb;
    #define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
    template<class T>inline void read(T &res) {
        char ch; int flg = 1; for(;!isdigit(ch=getc());)if(ch=='-')flg=-flg;
        for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0'); res*=flg;
    }
    typedef long long LL;
    
    const int MAXN = 100005;
    const int MAXV = 300005;
    const int INF = 0x3f3f3f3f;
    int n, q, tot, black, dfn[MAXN], fir[MAXN], cnt, seq[MAXV]; bool col[MAXN];
    struct edge { int to, nxt; }e[MAXN<<1];
    inline void add(int u, int v) {
        e[++cnt] = (edge) { v, fir[u] }, fir[u] = cnt;
        e[++cnt] = (edge) { u, fir[v] }, fir[v] = cnt;
    }
    void dfs(int u, int ff)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           {
        seq[++tot] = -6; //[
        seq[dfn[u]=++tot] = u;
        for(int i = fir[u]; i; i = e[i].nxt)
            if(e[i].to != ff) dfs(e[i].to, u);
        seq[++tot] = -9; //]
    }
    inline void chkmax(int &x, int y) { if(y > x) x = y; };
    inline int max(int x, int y, int z) { return max(max(x, y), z); }
    struct seg { //维护形如"]]]]][["的串
        int L, R, dis; //L:cnt(']'), R:cnt(']')
        int suf_plus, suf_minus; //suffix : max(L + R), max(L - R) 前缀最大值
        int pre_plus, pre_minus; //prefix : max(R + L), max(R - L) 后缀最大值
        inline void init(int i) {
            dis = -INF;
            L = (seq[i] == -9); //']'
            R = (seq[i] == -6); //'['
            if(seq[i] > 0 && col[seq[i]]) suf_plus = suf_minus = pre_plus = pre_minus = 0;
            else suf_plus = suf_minus = pre_plus = pre_minus = -INF;
        }
        inline friend seg operator +(const seg ls, const seg rs) {
            //MAIN IDEA: use "max()" to avoid category talk(用各种姿势的max避免分类讨论)
            int a = ls.L, b = ls.R, c = rs.L, d = rs.R; seg re;
        
            re.dis = max(ls.dis, rs.dis);
            chkmax(re.dis, ls.suf_plus + rs.pre_minus);
            chkmax(re.dis, ls.suf_minus + rs.pre_plus);
            
            // a]  <->  [d (a and d are symmetrical(对称))
            // [b  <->  c] (b and c are symmetrical)
            re.suf_plus = max(ls.suf_plus - c + d, ls.suf_minus + c + d, rs.suf_plus);
    		//前两个位置取max就避免了分类讨论,本来是要分(1.b>=c 2.b<c)两种情况考虑的.
    		//这样取max巧妙地避免写很多if(但也很有可能写爆)
            re.pre_plus = max(rs.pre_plus - b + a, rs.pre_minus + b + a, ls.pre_plus);
            
            re.suf_minus = max(ls.suf_minus + c - d, rs.suf_minus);
            re.pre_minus = max(rs.pre_minus + b - a, ls.pre_minus);
            
            if(b >= c) re.L = a, re.R = d + b-c;
            else re.L = a + c-b, re.R = d;
            
            return re;
        }
    }t[MAXV<<2];
    inline void upd(int i) { t[i] = t[i<<1] + t[i<<1|1]; } //简洁的update 2333
    void build(int i, int l, int r) {
        if(l == r) { t[i].init(l); return; }
        int mid = (l + r) >> 1;
        build(i<<1, l, mid);
        build(i<<1|1, mid+1, r);
        upd(i);
    }
    void modify(int i, int l, int r, int x) {
        if(l == r) { t[i].init(l); return; }
        int mid = (l + r) >> 1;
        if(x <= mid) modify(i<<1, l, mid, x);
        else modify(i<<1|1, mid+1, r, x);
        upd(i);
    }
    int main() {
        read(n);
        for(int x, y, i = 1; i < n; ++i)
            read(x), read(y), add(x, y);
        dfs(1, 0);
        for(int i = 1; i <= n; ++i) col[i] = 1, ++black;
        build(1, 1, tot);
        read(q); char s; int x;
        while(q--) {
            while(!isalpha(s=getc()));
            if(s == 'G') {
                if(!black) puts("-1");
                else if(black == 1) puts("0");
                else printf("%d
    ", t[1].dis);
            }
            else {
                read(x);
                if(!col[x]) ++black;
                else --black;
                col[x] ^= 1;
                modify(1, 1, tot, dfn[x]);
            }
        }
    }
    
    
  • 相关阅读:
    分页类
    验证码扭曲类
    model 概念(笔记)
    php单例模式
    php 无限极分类查找家谱树
    数组的合并
    无限极分类之查找子孙树
    android xml中的xliff属性
    android 悬浮覆盖状态栏的相关建议
    【jzoj】20190323比赛总结
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039335.html
Copyright © 2011-2022 走看看