BZOJ-2243] [SDOI2011 staining & Luo Valley P2486 (segment tree merging section + tree split chain)

Topic links: https://www.lydsy.com/JudgeOnline/problem.php?id=2243

Luo Valley:

Time limit 1.00s
Memory limit 125.00MB
 
BZOJ:
Time Limit: 20 Sec  Memory Limit: 512 MB

Description

Given an n-nodes m and unrooted trees operations, there are two types the operation:
1, the node b on a path to all node points are dyed to C;
2, a node query to the number of color segments on the path node b (successive same color are considered the same segment),
Such as "112221" by three segments: "11", "222" and "a."
You are to write a program in order to complete this m operations.

Input

The first line contains two integers n and m, respectively, and operand nodes;
The second line contains n positive integer n nodes initial color
The following lines contains two integers x and y, x and y represent Between an undirected edges.
The following lines each describing one operation:
"C abc" indicates that this is a dyeing operation, all the points on the node b to a path node (including a and b) are dyed to C;
"Q ab" indicates that this operation is a query to ask a node to node B (including a and b) the number of color segments on the path.

Output

For each query operation, output one line answer.

 

Sample Input

6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5

Sample Output

3
1
2

HINT

Number N <= 10 ^ 5, operands M <= 10 ^ 5, all colors and C is an integer between [0, 10 ^ 9].


 

A beginning title wrong. . . After correcting posture, emmmm, continuous segment, we should be able to think of tree line sections merge, leaving aside the tree in terms of graphics, we should be able to quickly write a program sequence number range segment, that is, bare tree line interval merger. However, this problem becomes a tree graphic, so we need to use the tree section, but need is worth noting that, after asking the interval segment tree complete range of consolidation needs to go heavy, a little trouble, after joining node in the tree section to climb the process will be repeated, that is to say, we need to re twice, once when asked to re-segment tree, a tree is the process of cross climb also need to go heavy.

 Remember mentioned before the interval merged segment tree operation, we use color and rcol lcol record node leftmost and rightmost color, if rcol left and to the right node of the node lcol equal, then we will be around when push_up after adding the value -1 sum node:

inline void push_up(int rt)
{
    tree[rt].sum=tree[ls].sum+tree[rs].sum;
    tree[rt].lc=tree[ls].lc;tree[rt].rc=tree[rs].rc;
    if (tree[ls].rc==tree[rs].lc) tree[rt].sum--;
}

 The next step is is to modify the operation, a continuous block all assigned to x, then we mark like a direct hit, then that is push_down operation, this is relatively simple, if a node exists mark, then his son about the sum = 1, col and all dyed the same color:

inline void push_down(int rt)
{
    tree[ls].f=tree[rs].f=1;
    tree[ls].sum=tree[rs].sum=1;
    tree[ls].lc=tree[ls].rc=tree[rt].lc;
    tree[rs].lc=tree[rs].rc=tree[rt].lc;
    tree[rt].f=0;
}

So it is easy to write the update:

inline void update(int l,int r,int rt,int L,int R,int col)
{
    if (l>=L && r<=R){
        tree[rt].lc=tree[rt].rc=col;
        tree[rt].sum=tree[rt].f=1;
        return;
    }
    if (tree[rt].f) push_down(rt);
    int mid=(l+r)>>1;
    if (mid>=L) update(lson,L,R,col);
    if (mid<R) update(rson,L,R,col);
    push_up(rt);
}

 

Comparison is downright query operations, this requires the merger between the cross, so that we can write for a node, if it's not completely left his son asked within range, to find the right son, if his son is not one to ask the right range, son left to find, otherwise explain about his son will have a part in the inquiry interval, then we recursively looking after adding determine if the left and right rcol == son of the son of a middle lcol then that is continuous, sum -:

inline int query(int l,int r,int rt,int L,int R)
{
    if (l>=L && r<=R){
        if (l==L) LC=tree[rt].lc;
        if (r==R) RC=tree[rt].rc;
        return tree[rt].sum;
    }
    int mid=(l+r)>>1;
    if (tree[rt].f) push_down(rt);
    if (mid>=R) return query(lson,L,R);
    else if (mid<L) return query(rson,L,R);
    intyears = query (lson, L, R) + query (rson, L, R);
    if (tree [br] .rc == tree [rs] .lc) ans-- ;
    return years; 
}

After the process is finished tree line sections merge bare tree cross-section of the run, twice dfs, and then modify the interval, the interval query, the first three do not say, set a board on OK, the query interval when climbing we have to go in a heavy, this is very troublesome. . . . My card quite a long time.

We LC and RC record each segment climbed the tree after the slope of the leftmost and rightmost color, in fact, every time the top section of the tree and the bottom of the chain, we then s1 and s2 record LC and RC, respectively, if the next time climbed the slope when the RC == s1, which is the last of the top and the bottom of this time the same color, then ans--.

When the same value to two in top Note that the wording of the tree and the general not the same cross-sectional, top value as it is climbing out of the process, query between the id [l] and id [r], but before we need to l, r depth of the judge, and then consider whether to exchange l and r:

inline int query_range(int l,int r)
{
    int s=0,s1=-1,s2=-1;
    while (top[l]!=top[r]){
        if (deep[top[l]]<deep[top[r]]) swap(l,r),swap(s1,s2);
        s+=query(1,n,1,id[top[l]],id[l]);
        if (RC==s1) s--;
        s1=LC;
        l=fa[top[l]];
    }
    if (deep[l]<deep[r]) swap(l,r),swap(s1,s2);
    s= Query + ( . 1 , n-, . 1 , ID [R & lt], ID [L]); // L must be placed back, l is the bottom, and to save the above consistent 
    IF (the RC == S1) S - Canton ;
     IF (the LC == S2) S - Canton ;
     return S; 
}
It should be noted that the values are equal to jump out after the top order before we climb and should be the same, l will be on the bottom, so as to ensure s1 and s2 not go wrong! 
The next is to go heavy, RC == s1 nothing to say, before said, but LC == s2 is what is it? LC is the foremost, s2 is the most distal switched path, as shown:

 The following is the AC codes:

#include <bits/stdc++.h>
using namespace std;

#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1

const int mac=1e5+10;

struct Edge
{
    int to,next;
}eg[mac<<1];
struct Tree
{
    int lc,rc,sum,f;
}tree[mac<<2];
int n,top[mac],head[mac],son[mac],dson[mac],tot=0;
int num=0,fa[mac],deep[mac],a[mac],id[mac],w[mac];

inline void add(int u,int v)
{
    eg[++num]=Edge{v,head[u]};
    head[u]=num;
}

inline void dfs1(int x,int f)
{
    son[x]=1;fa[x]=f;
    for (int i=head[x]; i!=-1; i=eg[i].next){
        int v=eg[i].to;
        if (v==f) continue;
        deep[v]=deep[x]+1;
        dfs1(v,x);
        son[x]+=son[v];
        if (son[dson[x]]<son[v]) dson[x]=v;
    }
}

inline void dfs2(int x,int tp)
{
    top[x]=tp,id[x]=++tot,w[tot]=a[x];
    if (!dson[x]) return;
    dfs2(dson[x],tp);
    for (int i=head[x]; i!=-1; i=eg[i].next){
        int v=eg[i].to;
        if (v==dson[x] || v==fa[x]) continue;
        dfs2(v,v);
    }
}

inline void push_up(int rt)
{
    tree[rt].sum=tree[ls].sum+tree[rs].sum;
    tree[rt].lc=tree[ls].lc;tree[rt].rc=tree[rs].rc;
    if (tree[ls].rc==tree[rs].lc) tree[rt].sum--;
}

inline void build(int l,int r,int rt)
{
    if (l==r){
        tree[rt].sum=1;
        tree[rt].lc=tree[rt].rc=w[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson);build(rson);
    push_up(rt);
}

inline void push_down(int rt)
{
    tree[ls].f=tree[rs].f=1;
    tree[ls].sum=tree[rs].sum=1;
    tree[ls].lc=tree[ls].rc=tree[rt].lc;
    tree[rs].lc=tree[rs].rc=tree[rt].lc;
    tree[rt].f=0;
}

inline void update(int l,int r,int rt,int L,int R,int col)
{
    if (l>=L && r<=R){
        tree[rt].lc=tree[rt].rc=col;
        tree[rt].sum=tree[rt].f=1;
        return;
    }
    if (tree[rt].f) push_down(rt);
    int mid=(l+r)>>1;
    if (mid>=L) update(lson,L,R,col);
    if (mid<R) update(rson,L,R,col);
    push_up(rt);
}

inline void update_range(int l,int r,int col)
{
    while (top[l]!=top[r]){
        if (deep[top[l]]<deep[top[r]]) swap(l,r);
        update(1,n,1,id[top[l]],id[l],col);
        l=fa[top[l]];
    }
    if (deep[l]>deep[r]) swap(l,r);
    update(1,n,1,id[l],id[r],col);
}

int LC,RC;

inline int query(int l,int r,int rt,int L,int R)
{
    if (l>=L && r<=R){
        if (l==L) LC=tree[rt].lc;
        if (r==R) RC=tree[rt].rc;
        return tree[rt].sum;
    }
    int mid=(l+r)>>1;
    if (tree[rt].f) push_down(rt);
    if (mid>=R) return query(lson,L,R);
    else if (mid<L) return query(rson,L,R);
    int ans=query(lson,L,R)+query(rson,L,R);
    if (tree[ls].rc==tree[rs].lc) ans--;
    return ans;
}

inline int query_range(int l,int r)
{
    int s=0,s1=-1,s2=-1;
    while (top[l]!=top[r]){
        if (deep[top[l]]<deep[top[r]]) swap(l,r),swap(s1,s2);
        s+=query(1,n,1,id[top[l]],id[l]);
        if (RC==s1) s--;
        s1=LC;
        l=fa[top[l]];
    }
    if (deep[l]<Deep [R & lt]) the swap (L, R & lt), the swap (S1, S2); 
    S + = Query ( . 1 , n-, . 1 , ID [R & lt], ID [L]); // L must be placed back, l to the bottom, above and to save the same 
    IF (the RC == S1) S - Canton ;
     IF (the LC == S2) S - Canton ;
     return S; 
} 

inline void  in ( int & X) 
{ 
    int F = 0 ;
     char CH = getchar ();
     the while (CH> ' . 9 ' || CH < ' 0 ' ) CH = getchar ();
     the while (CH <='9' && ch>='0') f=(f<<1)+(f<<3)+ch-'0',ch=getchar();
    x=f;
}

inline void debug_dfs()
{
    for (int i=1; i<=n; i++)
        printf ("%d:%d %d %d %d\n",i,id[i],deep[i],top[i],w[i]);
}

inline void debug_tree(int l,int r,int rt,int dp)
{
    printf("%d: %d %d %d\n", dp,tree[rt].sum,tree[rt].lc,tree[rt].rc);
    if (l==r) return;
    int mid=(l+r)>>1;
    debug_tree(lson,dp+1);debug_tree(rson,dp+1);
}

int main()
{
    //freopen("in.txt","r",stdin);
    memset(head,-1,sizeof head);
    int m;
    in(n);in(m);
    for (int i=1; i<=n; i++) in(a[i]);
    for (int i=1; i<n; i++) {
        int u,v;
        in(u);in(v);
        add(u,v);add(v,u);
    }
    dfs1(1,1);dfs2(1,1);
    build(1,n,1);
    //debug_dfs();
    //debug_tree(1,n,1,0);
    for (int i=1; i<=m; i++){
        char s[5];
        int l,r,w;
        scanf ("%s%d%d",s,&l,&r);
        if (s[0]=='C'){
            in(w);
            update_range(l,r,w);
        }
        else {
            int ans=query_range(l,r);
            printf ("%d\n",ans);
        }
    }
    return 0;
}
View Code

 

Guess you like

Origin www.cnblogs.com/lonely-wind-/p/12024454.html