• BZOJ 2243: [SDOI2011]染色


    题解:树链剖分细节题 口胡一下LCT也是可以的 只要维护一段的左右两个端点的颜色和长度合并即可

    树剖版本(入门的时候写的  好丑啊TAT)

    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<map>
    #include<set>
    #include<cstring>
    #include<cstdio>
    #define N 200005
    using namespace std;
    vector<int>vec[N];
    int pos;
    int son[N];
    int s[N];
    int n,m;
    void inte() {
        pos=0;
        for(int i=1; i<=n; i++)  son[i]=-1;
        return ;
    }
    int fa[N];
    int num[N];
    int deep[N];
    void dfs(int v,int pre,int w) {
        fa[v]=pre;
        num[v]=1;
        deep[v]=w;
        for(int i=0; i<vec[v].size(); i++) {
            int e=vec[v][i];
            if(e!=pre) {
                dfs(e,v,w+1);
                num[v]+=num[e];
                if(son[v]==-1||num[son[v]]<num[e]) {
                    son[v]=e;
                }
            }
        }
    }
    int tp[N];
    int p[N];
    int fp[N];
    void biaohao(int v,int sd) {
        tp[v]=sd;
        p[v]=++pos;
        fp[p[v]]=v;
        if(son[v]==-1)   return ;
        biaohao(son[v],sd);
        for(int i=0; i<vec[v].size(); i++) {
            int e=vec[v][i];
            if(e!=fa[v]&&e!=son[v])  biaohao(e,e);
        }
    }
    typedef struct node {
        int first;
        int end;
        int l;
        int r;
        int flag;
        int date;
    } node;
    node a[4*N];
    void built(int root,int first,int end) {
        if(first==end) {
            a[root].first=first;
            a[root].end=end;
            a[root].l=s[fp[first]];
            a[root].r=s[fp[first]];
            a[root].flag=-1;
            a[root].date=1;
            //cout<<first<<"  "<<a[root].l<<"     "<<a[root].date<<endl;
            return ;
        }
        int mid=(first+end)/2;
        built(root*2,first,mid);
        built(root*2+1,mid+1,end);
        a[root].first=a[root*2].first;
        a[root].end=a[root*2+1].end;
        a[root].l=a[root*2].l;
        a[root].r=a[root*2+1].r;
        a[root].flag=-1;
        if(a[root*2].r==a[root*2+1].l)  a[root].date=a[root*2].date+a[root*2+1].date-1;
        else a[root].date=a[root*2].date+a[root*2+1].date;
    //  cout<<a[root].l<<"  "<<a[root].r<<"  "<<a[root].date<<endl;
    }
    void U(int root,int first,int end,int l,int r,int e) {
        if(p[l]<=first&&end<=p[r]) {
            a[root].flag=-1;
            a[root].l=e;
            a[root].r=e;
            a[root].date=1;
            a[root*2].l=e;
            a[root*2].r=e;
            a[root*2].date=1;
            a[root*2+1].l=e;
            a[root*2+1].r=e;
            a[root*2+1].date=1;
            a[root*2].flag=e;
            a[root*2+1].flag=e;
        //  cout<<a[root].l<<"  "<<a[root].r<<"  "<<a[root].date<<endl;
            return ;
        }
        if(a[root].flag!=-1) {
            a[root*2].l=a[root].flag;
            a[root*2].r=a[root].flag;
            a[root*2].date=1;
            a[root*2+1].l=a[root].flag;
            a[root*2+1].r=a[root].flag;
            a[root*2+1].date=1;
            a[root*2].flag=a[root].flag;
            a[root*2+1].flag=a[root].flag;
            a[root].flag=-1;
        }
        int mid=(first+end)/2;
        if(p[l]<=mid)  U(root*2,first,mid,l,r,e);
        if(p[r]>mid)   U(root*2+1,mid+1,end,l,r,e);
        a[root].l=a[root*2].l;
        a[root].r=a[root*2+1].r;
        if(a[root*2].r==a[root*2+1].l)  a[root].date=a[root*2].date+a[root*2+1].date-1;
        else a[root].date=a[root*2].date+a[root*2+1].date;
    }
    int sum;
    int p1;
    int p2;
    int c1;
    int c2;
    int jump;
    int c3;
    int cc1;
    void Q(int root,int first,int end,int l,int r) {
            if(a[root].flag!=-1) {
            a[root*2].l=a[root].flag;
            a[root*2].r=a[root].flag;
            a[root*2].date=1;
            a[root*2+1].l=a[root].flag;
            a[root*2+1].r=a[root].flag;
            a[root*2+1].date=1;
            a[root*2].flag=a[root].flag;
            a[root*2+1].flag=a[root].flag;
            a[root].flag=-1;
        }
        if(p[l]==first){
                if(jump==0)  p1=a[root].l;
                else c3=a[root].l;
            }
        if(end==p[r]){
            if(jump==0)  p2=a[root].r;
            else p1=a[root].r;  
        }
        if(p[l]<=first&&end<=p[r]) {
            sum+=a[root].date;
            return ;
        }
        int mid=(first+end)/2;
        if(p[l]<=mid)  Q(root*2,first,mid,l,r);
        if(p[r]>mid)   Q(root*2+1,mid+1,end,l,r);
        if(p[l]<=mid&&mid<p[r]) sum-=(a[root*2].r==a[root*2+1].l);
        a[root].l=a[root*2].l;
        a[root].r=a[root*2+1].r;
        if(a[root*2].r==a[root*2+1].l)  a[root].date=a[root*2].date+a[root*2+1].date-1;
        else a[root].date=a[root*2].date+a[root*2+1].date;
    }
    int Sum(int u,int v) {
        int uu=tp[u];
        int vv=tp[v];
        sum=0;
        jump=-1;
        c1=-1;
        c2=-1;
        while(uu!=vv) {
            if(deep[uu]<deep[vv]) {
                swap(uu,vv);
                swap(u,v);
                swap(c1,c2);
            }
            Q(1,1,n,uu,u);
            sum=sum-(c1==p1);
        //  cout<<"---------------------"<<sum<<endl;
            c1=c3;
            u=fa[uu];
            uu=tp[u];
        }
        if(deep[u]>deep[v])  {
            swap(c1,c2);
            swap(u,v);
        }
        jump=0;
        cc1=-1;
        Q(1,1,n,u,v);
        sum=sum-(c1==p1);
        sum=sum-(c2==p2);
        return sum;
    }
    void Up(int u,int v,int e) {
        int uu=tp[u];
        int vv=tp[v];
        while(uu!=vv) {
            if(deep[uu]<deep[vv]) {
                swap(uu,vv);
                swap(u,v);
            }
            U(1,1,n,uu,u,e);
            u=fa[uu];
            uu=tp[u];
        }
        if(deep[u]>deep[v])  swap(u,v);
        U(1,1,n,u,v,e);
        return ;
    }
    int main() {
    //  freopen("1.txt","r",stdin);
    //  freopen("2.txt","w",stdout);
        scanf("%d%d",&n,&m);
        inte();
        int aa,bb;
        for(int i=1; i<=n; i++)  scanf("%d",&s[i]);
        for(int i=1; i<n; i++) {
            scanf("%d%d",&aa,&bb);
            vec[aa].push_back(bb);
            vec[bb].push_back(aa);
        }
        dfs(1,-1,1);
        biaohao(1,1);
        built(1,1,n);
        char ch;
        int u,v,e;
        for(int i=1; i<=m; i++) {
            scanf(" %c",&ch);
            if(ch=='C') {
                scanf("%d%d%d",&u,&v,&e);
                Up(u,v,e);
            } else if(ch=='Q') {
                scanf("%d%d",&u,&v);
                int t1=Sum(u,v);
                printf("%d
    ",t1);
            }
        }
        return 0;
    }
    

    2243: [SDOI2011]染色

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 10354  Solved: 3969
    [Submit][Status][Discuss]

    Description

    给定一棵有n个节点的无根树和m个操作,操作有2类:
    1、将节点a到节点b路径上所有点都染成颜色c;
    2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
    如“112221”由3段组成:“11”、“222”和“1”。
    请你写一个程序依次完成这m个操作。

    Input

    第一行包含2个整数n和m,分别表示节点数和操作数;
    第二行包含n个正整数表示n个节点的初始颜色
    下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
    下面 行每行描述一个操作:
    “C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
    “Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

    Output

    对于每个询问操作,输出一行答案。

    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

    数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

     

  • 相关阅读:
    HDU 2078 复习时间
    HDU 2076 夹角有多大
    邮票(codevs 2033)
    特种部队(codevs 1427)
    小a和uim之大逃离(洛谷 1373)
    地铁间谍(洛谷 2583)
    推销员(codevs 5126)
    小朋友的数字(codevs 3293)
    车站分级(洛谷 1983)
    Code(poj 17801)
  • 原文地址:https://www.cnblogs.com/wang9897/p/9460850.html
Copyright © 2020-2023  润新知