@loj - 3044 @ "ZJOI2019"최소 최대 검색


@기술@

나인은 가난한 소녀 플레이 게임을 좋아합니다. 그들의 게임의 수준을 향상하기 위해, 그녀는 무기 이론으로 무장하고 싶어. 이 질문에 유명한 최소 최대 검색하십시오.

가난한은 뿌리 트리가, 루트 노드 번호는 1입니다. 루트 노드의 깊이는 1로 부모 더한 깊이의 다른 노드의 깊이를 정의한다. 주어진 무게에서 리프 노드 동안, 가난한 정의하는 다음과 같은 방식 이외의 각 노드 값의 무게 :

对于深度为奇数的非叶子节点,它的权值是它所有子节点的权值最大值。
对于深度为偶数的非叶子节点,它的权值是它所有子节点的权值最小值。

처음에는 가난한 메이크업 오른쪽 리프 노드 번호 난의 난의 값과 바로 W.의 계산 된 값의 루트에 도착

지금, 악 Cedyks은 메이크업 변경에 대한 권리의 값의 루트 노드 일부 잎 노드의 가중치를 수정하려는. 도전이 시작된 후, Cedyks 무작위 통제의 비어 있지 않은 잎 노드 집합 S를 얻고, 리프 노드의 S의 가중치를 수정하는 몇 가지 에너지를 취할 수있다, 공격이 설계 양자를 Cedyks.

그러나, 리프 노드 I를 s의 에너지를 소비 리프 노드의 가중치를 수정하는 초기 가중치 나, 가중으로 수정 Cedyks이 Wi (WI 부정적인 포함하는 임의의 정수일 수있다) 것으로 가정 공격에서 다음 Cedyks 에너지, 그것은을 취한다 (| - w_i 전 | \ MAX_ {내가 \ S에서}) \ .

Cedyks 그는 항상 에너지의 최소 비용으로 오른쪽 루트 노드의 값의 변화를 만드는 것으로, 공격을 완료하는 데 최소한의 에너지를 수 있도록, 가능한 한 에너지를 절약하고 싶다. 따라서 W (S)의 세트를 제어 획득 한 후 에너지를 Cedyks 있음이 걸릴 S. 특히, 일부 세트 S에 대해, 가중치는 리프 노드의 모든 케이스 S에서 변경 될 수 있고, 루트 노드는 중량이 때, n으로 정의 된 W의 값을 변경하지 않을 것이다. 편의를 위해, 우리는 S.의 안정성 (S) 승 호출

m 리프 노드, 다른 비어 리프 노드 2 ^ m-1 종의 총 경우. 공격하기 전에, Cedyks는 그들이 필요로하는 에너지의 예상 비용을보고 싶다. 그는 간격 [L, R, 그 각각에 대한 K ∈ [L, R, 알고 싶어 제공, (S) = K w 세트 S 만족 수.

대답은 매우 클 수있다.하시기 바랍니다 998,244,353 모듈로 출력 쌍.

및 신속한 데이터 범위를
보장하기 위해 데이터의 100 %에 해당 2 <= N <= 200,000, 1 <= L <= R <= N.

@해결책@

안정성 K 감안 값의 범위에있는 각 잎의 무게가 변화 될 수 얻을 수있다.
그러나, 이러한 것이 더 없을 수도 | - | (W_i I = K가 \ MAX_ {내가 \ S에서}) \ , 안정도를 충족하지 못하는 정의가
나는 만족하는 모든 대표 우리 ANS [K]를 찾아 \ (MAX_ {내가 \에서 S} | 난 - w_i | \ 르 K \) 컬렉션의 수, 그리고 마지막으로는 차이를 확인하십시오.

잎은 잎 S는 최대 및 최소 값을 취할 수 있습니다 소요 취해야 루트의 최대 값을 변경 할 수 있습니다, 주어진 집합 S를 가정했다.
변화가 루트 중량 분을 초래할 수있는 경우 루트 웨이트는 w의 값을 설정 w <변경 루트 중량 최대 초래할 수 있다면, w>.

따라서, 생각할의 DP는 : DP 정의 [0/1]가 [I] 나 잎 서브 트리 트리 세트의 개수를 나타내며, 잎 중량 값 (I)의 최소 / 최대 후에 가중치를 변경 w 마지막으로 [0] [RT] + DP 얻을 DP [1] [RT]는 응답이다.
그러나 문제가, 법적인 컬렉션도 분 걸릴 수 있습니다 최대 또한 법적 가지고, 그것은 다시 카운트를합니다.

분에주의보다 작은 그 잎 노드가 실제로 변경하지 않은 W (이 최대 노드에 직접 또는 간접적으로 승 제거되어 있어야 있기 때문에, 변경되지 않았습니다).
마찬가지로, 변경 될 필요가 없으므로, 리프 노드보다 큰 w는 최대 변화.

그러나, 리프 노드 (W)에, 모두 커질 수도 있고 작아 질 수와 동일하다.
W는 모음 w 리프를 포함하는 경우에는 안정성이 반드시 1이고, 단 하나 개의 주와 동일하다 (루트 자연스럽게 변화, w는 가중치를 직접 변경 =).
우리는 승, 승 포함하지 않는 잎 수집을 강제로, 그리고 마지막으로 결합 할 수 있도록 기여가 포함되어 있습니다.

변경한다면 우리는 F를 나타낸다 [X]는 <표시 g, w는 [X]만을 나타내고 분 W>만을 나타내고 w DP 회 F, G로 얻을 수있다.
마지막으로,에 따라 계산 대답 w 잎의 수입니다.

각각의 O (n)의 복잡도 DP이지만, 우리는 모든 DP 값 [L, R]을 필요로한다.
노트 나 내가 직접 동적 DP로 변경한다 대부분 두 잎의 경우에 대응한다 + 1있다.

@accepted 코드 @

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 200000;
const int MOD = 998244353;
struct mint{
    int x;
    mint(int _x=0) : x(_x) {}
    friend mint operator + (mint a, mint b) {return a.x + b.x >= MOD ? a.x + b.x - MOD : a.x + b.x;}
    friend mint operator - (mint a, mint b) {return a.x - b.x < 0 ? a.x - b.x + MOD : a.x - b.x;}
    friend mint operator * (mint a, mint b) {return 1LL * a.x * b.x % MOD;}
    friend void operator *= (mint &a, mint b) {a = a * b;}
    friend void operator /= (mint &a, mint b) {
        int p = MOD - 2;
        while( p ) {
            if( p & 1 ) a *= b;
            b *= b;
            p >>= 1;
        }
    }
};
struct matrix{
    mint m[3][3];
    matrix() {
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                m[i][j] = 0;
    }
    friend matrix operator * (matrix A, matrix B) {
        matrix C;
        C.m[0][0] = A.m[0][0]*B.m[0][0] + A.m[0][1]*B.m[1][0] + A.m[0][2]*B.m[2][0];
        C.m[0][1] = A.m[0][0]*B.m[0][1] + A.m[0][1]*B.m[1][1] + A.m[0][2]*B.m[2][1];
        C.m[0][2] = A.m[0][0]*B.m[0][2] + A.m[0][1]*B.m[1][2] + A.m[0][2]*B.m[2][2];
        C.m[1][0] = A.m[1][0]*B.m[0][0] + A.m[1][1]*B.m[1][0] + A.m[1][2]*B.m[2][0];
        C.m[1][1] = A.m[1][0]*B.m[0][1] + A.m[1][1]*B.m[1][1] + A.m[1][2]*B.m[2][1];
        C.m[1][2] = A.m[1][0]*B.m[0][2] + A.m[1][1]*B.m[1][2] + A.m[1][2]*B.m[2][2];
        C.m[2][0] = A.m[2][0]*B.m[0][0] + A.m[2][1]*B.m[1][0] + A.m[2][2]*B.m[2][0];
        C.m[2][1] = A.m[2][0]*B.m[0][1] + A.m[2][1]*B.m[1][1] + A.m[2][2]*B.m[2][1];
        C.m[2][2] = A.m[2][0]*B.m[0][2] + A.m[2][1]*B.m[1][2] + A.m[2][2]*B.m[2][2];
        return C;
    }
}I;
mint pw2[MAXN + 5];
void init() {
    pw2[0] = 1;
    for(int i=1;i<=MAXN;i++)
        pw2[i] = 2*pw2[i-1];
    I.m[0][0] = I.m[1][1] = I.m[2][2] = 1;
}
struct edge{
    int to; edge *nxt;
}edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt = edges;
void addedge(int u, int v) {
    edge *p = (++ecnt);
    p->to = v, p->nxt = adj[u], adj[u] = p;
    p = (++ecnt);
    p->to = u, p->nxt = adj[v], adj[v] = p;
}
int val[MAXN + 5], dep[MAXN + 5];
int fa[MAXN + 5], siz[MAXN + 5], hvy[MAXN + 5];
void dfs1(int x, int f) {
    fa[x] = f, siz[x] = 1, hvy[x] = 0, dep[x] = dep[f] + 1;
    for(edge *p=adj[x];p;p=p->nxt) {
        if( p->to == f ) continue;
        dfs1(p->to, x), siz[x] += siz[p->to];
        val[x] = (val[x] ? ((dep[x] & 1) ? max(val[x], val[p->to]) : min(val[x], val[p->to])) : val[p->to]);
        if( siz[hvy[x]] < siz[p->to] )
            hvy[x] = p->to;
    }
    if( !hvy[x] ) val[x] = x;
}
struct node{
    int z; mint x;
    node(int _x=0) : z(0), x(_x) {}
    friend void operator *= (node &a, mint b) {
        if( b.x == 0 ) a.z++;
        else a.x *= b;
    }
    friend void operator /= (node &a, mint b) {
        if( b.x == 0 ) a.z--;
        else a.x /= b;
    }
    mint key() {return z ? 0 : x;}
}a[MAXN + 5], b[MAXN + 5];
mint f[MAXN + 5], g[MAXN + 5];
/*
f -> (only modify leaf > v1, vi < w)
g -> (only modify leaf < v1, vi > w)
*/
int lc1[MAXN + 5], lc2[MAXN + 5]; 
int top[MAXN + 5], dfn[MAXN + 5], tid[MAXN + 5], btm[MAXN + 5], dcnt;
int d;
int ff(int x) {return (x > val[1] && x - d < val[1]) + (x < val[1]);}
int gg(int x) {return (x < val[1] && x + d > val[1]) + (x > val[1]);}
//选入集合 + 不选入集合
int dfs2(int x, int tp) {
    top[x] = tp, dfn[++dcnt] = x, tid[x] = dcnt;
    if( !hvy[x] ) {
/*
        f[x] = (x > val[1] && x - 0 < val[1]) + (x < val[1]);
        g[x] = (x < val[1] && x + 0 > val[1]) + (x > val[1]);
*/
        f[x] = ff(x), g[x] = gg(x);
        lc1[x] += (x > val[1]), lc2[x] += (x < val[1]);
        return btm[x] = x;
    }
    btm[x] = dfs2(hvy[x], tp), lc1[x] += lc1[hvy[x]], lc2[x] += lc2[hvy[x]];
    for(edge *p=adj[x];p;p=p->nxt)
        if( p->to != hvy[x] && p->to != fa[x] )
            dfs2(p->to, p->to), lc1[x] += lc1[p->to], lc2[x] += lc2[p->to];
    if( dep[x] & 1 ) {
        a[x] = b[x] = 1;
        for(edge *p=adj[x];p;p=p->nxt)
            if( p->to != hvy[x] && p->to != fa[x] )
                a[x] *= f[p->to], b[x] *= (pw2[lc2[p->to]] - g[p->to]);
        f[x] = a[x].key()*f[hvy[x]];
        g[x] = pw2[lc2[x]] - b[x].key()*pw2[lc2[hvy[x]]] + b[x].key()*g[hvy[x]];
    }
    else {
        a[x] = b[x] = 1;
        for(edge *p=adj[x];p;p=p->nxt)
            if( p->to != hvy[x] && p->to != fa[x] )
                a[x] *= g[p->to], b[x] *= (pw2[lc1[p->to]] - f[p->to]);
        g[x] = a[x].key()*g[hvy[x]];
        f[x] = pw2[lc1[x]] - b[x].key()*pw2[lc1[hvy[x]]] + b[x].key()*f[hvy[x]];
    }
    return btm[x];
}
matrix getM(int x) {
    if( !hvy[x] ) return I;
    matrix M;
    if( dep[x] & 1 ) {
        M.m[0][0] = a[x].key(), M.m[1][1] = b[x].key();
        M.m[1][2] = pw2[lc2[x]] - b[x].key()*pw2[lc2[hvy[x]]];
        M.m[2][2] = 1;
    }
    else {
        M.m[1][1] = a[x].key(), M.m[0][0] = b[x].key();
        M.m[0][2] = pw2[lc1[x]] - b[x].key()*pw2[lc1[hvy[x]]];
        M.m[2][2] = 1;
    }
    return M;
}
struct segtree{
    #define lch (x << 1)
    #define rch (x << 1 | 1)
    struct node{
        int le, ri;
        matrix M;
    }t[4*MAXN + 5];
    void pushup(int x) {t[x].M = t[lch].M * t[rch].M;}
    void build(int x, int l, int r) {
        t[x].le = l, t[x].ri = r;
        if( l == r ) {
            t[x].M = getM(dfn[l]);
            return ;
        }
        int m = (l + r) >> 1;
        build(lch, l, m), build(rch, m + 1, r);
        pushup(x);
    }
    void update(int x, int p) {
        if( p > t[x].ri || p < t[x].le )
            return ;
        if( t[x].le == t[x].ri ) {
            t[x].M = getM(dfn[p]);
            return ;
        }
        update(lch, p), update(rch, p);
        pushup(x);
    }
    matrix query(int x, int l, int r) {
        if( l > t[x].ri || r < t[x].le )
            return I;
        if( l <= t[x].le && t[x].ri <= r )
            return t[x].M;
        return query(lch, l, r) * query(rch, l, r);
    }
}T;
void modify(int x) {
    while( fa[top[x]] ) {
        x = top[x];
        if( dep[fa[x]] & 1 )
            a[fa[x]] /= f[x], b[fa[x]] /= (pw2[lc2[x]] - g[x]);
        else a[fa[x]] /= g[x], b[fa[x]] /= (pw2[lc1[x]] - f[x]);
        matrix M = T.query(1, tid[x], tid[btm[x]]);
        f[x] = M.m[0][0]*ff(btm[x]) + M.m[0][2];
        g[x] = M.m[1][1]*gg(btm[x]) + M.m[1][2];
        if( dep[fa[x]] & 1 )
            a[fa[x]] *= f[x], b[fa[x]] *= (pw2[lc2[x]] - g[x]);
        else a[fa[x]] *= g[x], b[fa[x]] *= (pw2[lc1[x]] - f[x]);
        x = fa[x];
        T.update(1, tid[x]);
    }
}
mint get_ans() {
    matrix M = T.query(1, tid[1], tid[btm[1]]);
    mint f1 = M.m[0][0]*ff(btm[1]) + M.m[0][2];
    mint g1 = M.m[1][1]*gg(btm[1]) + M.m[1][2];
    return pw2[lc1[1] + lc2[1]] - (pw2[lc1[1]] - f1) * (pw2[lc2[1]] - g1);
}
int n, L, R;
mint ans[MAXN + 5];
int read() {
    int x = 0; char ch = getchar();
    while( ch > '9' || ch < '0' ) ch = getchar();
    while( '0' <= ch && ch <= '9' ) x = 10*x + ch - '0', ch = getchar();
    return x;
}
void write(int x) {
    if( !x ) return ;
    write(x/10);
    putchar(x%10 + '0');
}
int main() {
    init(), n = read(), L = read(), R = read();
    for(int i=1;i<n;i++) {
        int u = read(), v = read();
        addedge(u, v);
    }
    dfs1(1, 0), dfs2(1, 1), T.build(1, 1, n);
    for(d=1;d<=n;d++) {
        int p = (val[1] + 1 - d);
        if( p < val[1] && p >= 1 && !hvy[p] )
            modify(p);
        p = (val[1] - 1 + d);
        if( p > val[1] && p <= n && !hvy[p] )
            modify(p);
        ans[d] = get_ans();
    }
    ans[n] = pw2[lc1[1]+lc2[1]] - ans[n] - 1;
    for(int i=n-1;i>=1;i--) ans[i] = ans[i] - ans[i-1];
    ans[1] = ans[1] + pw2[lc1[1]+lc2[1]];
    for(int i=L;i<=R;i++) {
        if( ans[i].x ) write(ans[i].x); else putchar('0');
        putchar(i == n ? '\n' : ' ');
    }
}

@세부@

로컬 큰 테스트 샘플은 AC의 5 초를 실행하는 이유를 모르겠어요 그래서 실제로 지불.

추천

출처www.cnblogs.com/Tiw-Air-OAO/p/11915347.html