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\n",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]之间。

 

posted @ 2018-08-11 19:47  wang9897  阅读(96)  评论(0编辑  收藏  举报