[LA 7402] colorful tree 데이터 구조

17687 단어 데이터 구조
As we all know, frogs live on trees and have different colors. N frogs are living on a tree. The tree consists of N nodes with node 1 as the root, each frog occupies a node. Frogs have different colors, and can change colors as they like. On each day, all the frogs living on a certain sub-tree will change its color. The root of the sub-tree, and the color they change to, is given to the frog king. As the frog king, sometimes he may wonder, how many different colors of frog are there in a certain sub-tree? It turns to you to solve the problem for the king. Input First line contains an integer T, which indicates the number of test cases. Every test case begins with an integers N, which is the numbers of nodes in the tree. The following N − 1 lines describe the edges of the tree, and every line is formatted as ‘u v’, which indicates there is a edge between node u and node v. The next line contains N intergers, c1, c2, · · ·, cN , and ci is the initial color of the frog living at node i. Then a number M follows, which indicates the number of queries, and following M lines describe the quries as format bellow. operation format description modify color 0 u c change the color of all frogs in the sub-tree rooted at node u to c query 1 u query how many different colors of frog are there in the sub-tree rooted at node u Restrictions: • 1 ≤ T ≤ 100. • For 85% data, 1 ≤ N, M ≤ 1000. • for 100% data, 1 ≤ N, M ≤ 105 . • for every node, 1 ≤ ci ≤ N. • for every edge, 1 ≤ u, v ≤ N. • for every query, 1 ≤ u, c ≤ N. Output For every test case, you should output ‘Case #x:’ first, where x indicates the case number and counts from 1. Then for each query operation, output the number of different colors. Sample Input 1 5 1 2 1 3 2 5 2 4 1 2 3 4 5 6 1 1 0 4 2 1 1 1 2 0 2 3 1 2 Sample Output Case #1: 5 4 2 1
원래 의 문제 전송 문 WC 에서 유 여 가 씨 가 추천 한 문 제 는 그 당시 에 많은 동료 들 과 오랫동안 생각 했 는데 어떤 사람 이 괜 찮 은 방법 (그런데 잊 어 버 렸 다.) 을 주 고 유 에 게 메 일 로 물 었 다. 유 는 나 에 게 문 제 를 풀 어 주 었 다. 보고 나 서 야 어떻게 해 야 할 지 대충 알 게 되 었 다.이 문 제 를 통 해 나무 에서 하 는 일 은 직접 서열 에서 하 는 것 보다 더 나 쁘 지 않다 는 것 을 깨 달 았 다.(WC 상영 원 커 뮤 니 케 이 션 을 인용 하고 싶 을 때..................................................................................zgy 신 번 의 한 마디 는 그다지 합 리 적 이지 않 아 보 이 는 이 사실 뒤의 원인 을 잘 설명 했다. "자 나 무 는 n 개 (구간 에 O (n2) 개 만 있다."한 걸음 한 걸음 분석 해 보 자.서술 의 편 의 를 위해 우 리 는 형식 화 된 정 의 를 내 렸 다. 그것 은 이원 그룹 (u, c) 이다. 즉, 뿌리 노드 가 u 인 서브 트 리 의 모든 결점 의 색 을 모두 c 로 수정 하 는 것 이다.통일 을 위해 서 는 모든 결점 의 초기 색상 도 한 번 의 수정 으로 보 는 것 이 좋 습 니 다.한 그루 의 나 무 를 수정 할 때, 우 리 는 폭력 적 으로 이전에 이 나무 에 존 재 했 던 수정 사항 을 순서대로 찾 아 폭력 적 으로 삭제 해 야 한다.분명히 모든 수정 은 u 의 모든 조상 결점 에 영향 을 줄 수 있 지만 어떻게 빠 뜨리 지 않 는 통 계 를 중시 하지 않 습 니까?사실 우 리 는 한 그루 의 나무 에서 같은 색깔 의 점 중 dfs 순서 가 가장 큰 점 이 그것 에 미 치 는 영향 만 고려 하면 된다.이 를 위해 다음 과 같은 방법 을 사용 하 는 것 도 좋 습 니 다. 색깔 이 같은 모든 점 을 dfs 순서 로 배열 하고 a1, a2, a3,...................................................................................................ak 는 뿌리 에 있 는 경로 에 직접적인 영향 을 주면 됩 니 다.이렇게 해서 우 리 는 특정한 색깔 에 대해 dfs 서열 의 가장 큰 점 의 영향 만 을 고려 했다 는 것 을 보증 했다.같은 색상 의 점 집합 과 모든 수 정 된 집합 은 밸 런 스 트 리 로 유지 할 수 있 습 니 다.어떤 점 을 물 을 때 모든 수정 이 그 에 미 친 영향 을 포함 하 는 것 외 에 도 고려 해 야 한다. 만약 에 이 점 이 어떠한 수정 (즉, 수정 한 u 가 하나 도 없다) 에 속 하지 않 는 다 면 우 리 는 그의 실제 색 (이것 은 선분 트 리 를 사용 하여 간단하게 유지 할 수 있다) 을 알 아야 한다. 또한 이런 색 이 서브 트 리 의 특정한 수정 에 나 타 났 는 지 알 아야 한다.(그런 색 의 밸 런 스 트 리 에서 찾 으 면 됩 니 다) 답 을 하나 더 붙 여야 하 는 지 판단 합 니 다. 위의 서술 에 따 르 면 이 문제 가 트 리 의 경로 업데이트 + 단일 조회 로 바 뀌 었 음 을 알 수 있 습 니 다. 정상 인 들 은 이 걸 보면 트 리 체인 분할 + 트 리 배열 을 사용 합 니 다.아니면 엘 시 티 가 해 결 했 나 봐 요.
#include
#include
#include
#include
#define clr(a,b) memset(a,b,sizeof(a))
#define maxn 100000
#define mid (l+r>>1)
using namespace std;
struct EDGE{
    int u,v,next;
}edge[2*maxn+10];
int head[maxn+10],pp;
void adde(int u,int v){
    edge[++pp]=(EDGE){u,v,head[u]};
    head[u]=pp;
}
int fa[maxn+10],de[maxn+10],top[maxn+10],id[maxn+10],sz[maxn+10],hs[maxn+10];
int son[maxn+10],bro[maxn+10];
int dfn[maxn+10],c[maxn+10],clo;
int n;
//              
struct segmentree{
    int lc[2*maxn+10],rc[2*maxn+10],setv[2*maxn+10],cnt;
    void init(){
        clr(setv,-1);
        int o;
        cnt=0;
        maketree(o,1,n);        
    }
    void maketree(int &o,int l,int r){
        o=++cnt;
        if(l==r)return;
        int m=mid;
        maketree(lc[o],l,m);
        maketree(rc[o],m+1,r);
    }
    void pushdown(int o){
        if(setv[o]==-1)return;
        setv[lc[o]]=setv[rc[o]]=setv[o];
        setv[o]=-1;
    }
    void update(int o,int l,int r,int ql,int qr,int v){
        if(ql<=l&&r<=qr)setv[o]=v;
        else{
            pushdown(o);
            int m=mid;
            if(ql<=m)update(lc[o],l,m,ql,qr,v);
            if(qr>m)update(rc[o],m+1,r,ql,qr,v);
        }
    }
    int query(int o,int l,int r,int p){
        if(setv[o]!=-1)return setv[o];
        int m=mid;
        if(p<=m)return query(lc[o],l,m,p);
        return query(rc[o],m+1,r,p);        
    }
}seg;
//   get√    struct   ,          ……
struct cmp{bool operator()(const int&a,const int &b){return dfn[a]set<int,cmp> S[maxn+10],d;
struct fenwicktree{
    int c[maxn+10];
    void clear(){clr(c,0);}
    void add(int x,int v){
        while(x<=n){
            c[x]+=v;
            x+=x&-x;
        }
    }
    int sum(int p){
        int ret=0,cp=seg.query(1,1,n,dfn[p]);
        set<int>::iterator it=S[cp].lower_bound(p);
        //                  
        if(d.find(p)==d.end()&&(it==S[cp].end()||dfn[*it]>=dfn[p]+sz[p]))ret=1;
        int x=id[p];
        while(x){
            ret+=c[x];
            x-=x&-x;
        }
        return ret;
    }
}fen;
void update(int l,int r,int v){
    fen.add(l,v);
    fen.add(r+1,-v);
}
//         = =      
void lca(int u,int v,int val,int f){
    for(;;){
        if(top[u]==top[v]){
            if(de[u]>=de[v])update(id[v]+(f==0),id[u],val); 
            break;
        }else{
            if(de[top[u]]>=de[top[v]]){
                update(id[top[u]],id[u],val);
                u=fa[top[u]];
            }else v=fa[top[v]];
        }
    }
}
void del(int u){
    set<int>::iterator it=S[c[u]].find(u);
    int p=0,s;
    if(it!=S[c[u]].begin()){
        p=*(--it);
        ++it;
    }
    if(++it!=S[c[u]].end())s=*it;
    else s=1;
    if(p){
        lca(p,u,-1,0);
        lca(p,s,1,s==1);
    }
    lca(u,s,-1,s==1);
    S[c[u]].erase(u);
}
void modify(int u,int nc){
    seg.update(1,1,n,dfn[u],dfn[u]+sz[u]-1,nc);
    set<int>::iterator it,it0;
    //    ,          = =          
    for(it=d.lower_bound(u);it!=d.end();){
        int v=*it;
        if(dfn[v]>=dfn[u]+sz[u])break;
        del(v);
        it0=it++;
        d.erase(it0);
    }
    d.insert(u);
    c[u]=nc;
    S[nc].insert(u);
    it=S[nc].find(u);
    int p=0,s;
    if(it!=S[nc].begin()){
        p=*(--it);
        ++it;
    }
    //              
    if(++it!=S[nc].end())s=*it;
    else s=1;
    if(p){
        lca(p,s,-1,s==1);
        lca(p,u,1,0);
    }
    lca(u,s,1,s==1);
}
//  dfs    
void dfs1(int u){
    dfn[u]=++clo;
    sz[u]=1;
    for(int i=head[u];i;i=edge[i].next){
        int v=edge[i].v;
        if(v!=fa[u]){
            bro[v]=son[u];
            son[u]=v;
            fa[v]=u;
            de[v]=de[u]+1;
            dfs1(v);
            sz[u]+=sz[v];
            if(sz[v]>sz[hs[u]])hs[u]=v;
        }
    }
}
void dfs2(int u,int t){
    id[u]=++clo;
    top[u]=t;
    if(hs[u])dfs2(hs[u],t);
    for(int v=son[u];v;v=bro[v])if(v!=hs[u]){
        top[v]=v;
        dfs2(v,v);
    }
}
//     
void dfs3(int u){
    modify(u,c[u]);
    for(int v=son[u];v;v=bro[v])dfs3(v);
}
int main(){
    freopen("7402.in","r",stdin);
    freopen("wode.out","w",stdout);
    int T;
    scanf("%d",&T);
    for(int t=1;t<=T;t++){
        printf("Case #%d:
"
,t); fen.clear(); d.clear(); pp=clo=0; clr(head,0); clr(hs,0); clr(son,0); scanf("%d",&n); seg.init(); for(int i=1;iint u,v; scanf("%d%d",&u,&v); adde(u,v); adde(v,u); } for(int i=1;i<=n;i++){ scanf("%d",&c[i]); S[i].clear(); } dfs1(1); clo=0; dfs2(1,1); dfs3(1); int q; scanf("%d",&q); while(q--){ int k,u,nc; scanf("%d%d",&k,&u); if(k==0){ scanf("%d",&nc); modify(u,nc); }else printf("%d
"
,fen.sum(u)); } } return 0; }

좋은 웹페이지 즐겨찾기