[BZOJ - 2243] 染色 (动态树LCT)

50 篇文章 0 订阅
3 篇文章 0 订阅

题意:

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c;

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),

如“112221”由3段组成:“11”、“222”和“1”。

请你写一个程序依次完成这m个操作。

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

题解:

动态书树上带修改查询

#include <bits/stdc++.h>
#define FOR(i,s,t) for(int i=(s);i<=(t);i++)
#define ROF(i,s,t) for(int i=(s);i>=(t);i--)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const ll mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int readInt(){
    int x=0;
    bool sign=false;
    char c=getchar();
    while(!isdigit(c)){
        sign=c=='-';
        c=getchar();
    }
    while(isdigit(c)){
        x=x*10+c-'0';
        c=getchar();
    }
    return sign?-x:x;
}
ll readLong(){
    ll x=0;
    bool sign=false;
    char c=getchar();
    while(!isdigit(c)){
        sign=c=='-';
        c=getchar();
    }
    while(isdigit(c)){
        x=x*10+c-'0';
        c=getchar();
    }
    return sign?-x:x;
}
string readString(){
    string s;
    char c=getchar();
    while(isspace(c)){
        c=getchar();
    }
    while(!isspace(c)){
        s+=c;
        c=getchar();
    }
    return s;
}
const int MAXN=1e5+10;
struct node{
    int v,upv,downv,sum,lz;
    bool lz_rev;
    node *p,*s[2];
    void build(int x)
    {
        v=upv=downv=x;
        sum=1;
        lz=0;
        lz_rev=0;
        p=s[0]=s[1]=NULL;
    }
}*root[MAXN];
void update(node *now)
{
    if(!now) return;
    now->upv=now->s[0]?now->s[0]->upv:now->v;
    now->downv=now->s[1]?now->s[1]->downv:now->v;
    now->sum=1;
    if(now->s[0]) now->sum+=now->s[0]->sum-(now->v==now->s[0]->downv);
    if(now->s[1]) now->sum+=now->s[1]->sum-(now->v==now->s[1]->upv);
}
void print(node *now,int x)
{
    if(!now) return;
    now->v=now->upv=now->downv=x;
    now->sum=1;
    now->lz=x;
}
void rev(node *now)
{
    if(now)
    {
        swap(now->s[0],now->s[1]);
        swap(now->upv,now->downv);
        now->lz_rev^=1;
    }
}
void down(node *now)
{
    if(now->lz_rev)
    {
        rev(now->s[0]);
        rev(now->s[1]);
        now->lz_rev=0;
    }
    if(now->lz)
    {
        print(now->s[0],now->lz);
        print(now->s[1],now->lz);
        now->lz=0;
    }
    update(now);
}
void link(node *f,node *x,bool d)
{
    f->s[d]=x;
    if(x) x->p=f;
    update(f);
}
bool is_root(node *now){return !now->p||now!=now->p->s[0]&&now!=now->p->s[1];}
void rotate(node *now,bool d)
{
    node *x=now->s[d],*p=now->p;
    bool flag=is_root(now);
    link(now,x->s[d^1],d);
    link(x,now,d^1);
    if(flag) x->p=p;
    else link(p,x,now==p->s[1]);
}
stack<node*>s;
void splay(node *now)
{
    s.push(now);
    for(node *i=now;!is_root(i);i=i->p) s.push(i->p);
    while(!s.empty()) down(s.top()),s.pop();
    while(!is_root(now))
    {
        node *cur=now->p;
        bool d1=now==cur->s[1];
        if(is_root(cur))
        {
            rotate(cur,d1);
            return;
        }
        node *x=cur->p;
        bool d2=cur==x->s[1];
        if(d1^d2) rotate(cur,d1),rotate(x,d2);
        else rotate(x,d2),rotate(cur,d1);
    }
}
void access(node *now)
{
    node *x=NULL,*st=now;
    while(now)
    {
        splay(now);
        link(now,x,1);
        x=now;
        now=now->p;
    }
    splay(st);
}
void set_root(node *now){access(now),rev(now);}
void extract(node *x,node *y){set_root(x),access(y);}
void con(node *x,node *y){set_root(x),x->p=y;}
int n,m;
int main()
{
    //freopen("2.in", "r", stdin);
    //freopen("out.txt","w",stdout);
    //ios::sync_with_stdio(0);
    //cin>>n>>m;
    n = readInt();
    m = readInt();
    for(int i=1;i<=n;++i)
    {
        int a = readInt();
        root[i]=new node;
        root[i]->build(a);
    }
    for(int i=1;i<n;++i)
    {
        int a = readInt(), b= readInt();
        con(root[a],root[b]);
    }
    while(m--)
    {
        char op=getchar();
        while(isspace(op)){
            op=getchar();
        }
        int x,y,z;
        if(op=='C')
        {
            x = readInt();
            y = readInt();
            z = readInt();
            extract(root[x],root[y]);
            print(root[y],z);
        }
        else
        {
            x = readInt();
            y = readInt();
            extract(root[x],root[y]);
            printf("%d\n",root[y]->sum);
        }
    }
    //
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值