BZOJ 2243 染色

呀这个还有代码编辑器啊。。我今天才发现。

链剖水题。维护区间左端点和右端点的颜色。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxv 200500
#define maxe 200500
#define maxn 805000
using namespace std;
int n,m,num[maxv],x,y,root=1,nume=0,tot=0,cnt=0,g[maxv];
int dis[maxv],top[maxv],fath[maxv],size[maxv],son[maxv],w[maxv],fw[maxv];
int ls[maxn],rs[maxn],lpos[maxn],rpos[maxn],lazy[maxn],sum[maxn];
int a,b,c;
bool vis[maxv],fff[maxv];
char type[5];
struct edge
{
    int v,nxt;
}e[maxe];
void addedge(int u,int v)
{
    e[++nume].v=v;
    e[nume].nxt=g[u];
    g[u]=nume;
}
void dfs1(int x)
{
    son[x]=0;size[x]=1;
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (v!=fath[x])
        {
            fath[v]=x;
            dis[v]=dis[x]+1;
            dfs1(v);
            if (size[v]>size[son[x]])
                son[x]=v;
            size[x]=size[x]+size[v];
        }
    }
}
void dfs2(int x,int fa)
{
    w[x]=++cnt;fw[cnt]=x;top[x]=fa;
    if (son[x]!=0) dfs2(son[x],fa);
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if ((v!=fath[x]) && (v!=son[x]))
            dfs2(v,v);
    }
}
void build(int &now,int left,int right)
{
    now=++tot;lpos[now]=0;rpos[now]=0;lazy[now]=-1;
    if (left==right)
    {
        int regis;
        regis=num[fw[left]];
        lpos[now]=regis;rpos[now]=regis;
        sum[now]=1;
        return;
    }
    int mid=(left+right)>>1;
    build(ls[now],left,mid);
    build(rs[now],mid+1,right);
    lpos[now]=lpos[ls[now]];rpos[now]=rpos[rs[now]];
    sum[now]=sum[ls[now]]+sum[rs[now]];
    if (rpos[ls[now]]==lpos[rs[now]]) sum[now]=sum[now]-1;
}
void pushdown(int now,int left,int right)
{
    if (lazy[now]!=-1)
    {
        lazy[ls[now]]=lazy[now];lazy[rs[now]]=lazy[now];
        lpos[ls[now]]=lazy[now];lpos[rs[now]]=lazy[now];
        rpos[ls[now]]=lazy[now];rpos[rs[now]]=lazy[now];
        sum[ls[now]]=1;sum[rs[now]]=1;
        lazy[now]=-1;
    }
}
void modify(int now,int left,int right,int l,int r,int p)
{
    pushdown(now,left,right);
    if ((left==l) && (right==r))
    {
        lazy[now]=p;sum[now]=1;
        lpos[now]=p;rpos[now]=p;
        return;
    }
    int mid=(left+right)>>1;
    if (r<=mid) modify(ls[now],left,mid,l,r,p);
    else if (l>=mid+1) modify(rs[now],mid+1,right,l,r,p);
    else
    {
        modify(ls[now],left,mid,l,mid,p);
        modify(rs[now],mid+1,right,mid+1,r,p);
    }
    lpos[now]=lpos[ls[now]];rpos[now]=rpos[rs[now]];
    sum[now]=sum[ls[now]]+sum[rs[now]];
    if (rpos[ls[now]]==lpos[rs[now]]) sum[now]=sum[now]-1;
}
int ask(int now,int left,int right,int l,int r)
{
    pushdown(now,left,right);
    if ((left==l) && (right==r))
        return sum[now];
    int mid=(left+right)>>1;
    if (r<=mid) return ask(ls[now],left,mid,l,r);
    else if (l>=mid+1) return ask(rs[now],mid+1,right,l,r);
    else
    {
        int regis=0;
        regis=ask(ls[now],left,mid,l,mid)+ask(rs[now],mid+1,right,mid+1,r);
        if (rpos[ls[now]]==lpos[rs[now]]) regis--;
        return regis;
    }
}
int find(int now,int left,int right,int p)
{
    pushdown(now,left,right);
    if (left==p) return lpos[now];
    int mid=(left+right)>>1;
    if (p<=mid) return find(ls[now],left,mid,p);
    else return find(rs[now],mid+1,right,p);
}
void work1()
{
    scanf("%d%d%d",&a,&b,&c);
    int f1=top[a],f2=top[b];
    while (f1!=f2)
    {
        if (dis[f1]<dis[f2]) {swap(f1,f2);swap(a,b);}
        modify(root,1,cnt,w[f1],w[a],c);
        a=fath[f1];f1=top[a];
    }
    if (dis[a]>dis[b]) swap(a,b);
    modify(root,1,cnt,w[a],w[b],c);
}
void work2()
{
    int ans=0;
    scanf("%d%d",&a,&b);
    int f1=top[a],f2=top[b];
    while (f1!=f2)
    {
        if (dis[f1]<dis[f2]) {swap(f1,f2);swap(a,b);}
        ans=ans+ask(root,1,cnt,w[f1],w[a]);
        a=fath[f1];
        if (find(root,1,cnt,w[a])==find(root,1,cnt,w[f1]))
            ans--;
        f1=top[a];
    }
    if (dis[a]>dis[b]) swap(a,b);
    ans=ans+ask(root,1,cnt,w[a],w[b]);
    printf("%d\n",ans);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&num[i]);
    for (int i=1;i<=n-1;i++)
    {
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    dfs1(root);
    dfs2(root,root);
    build(root,1,cnt);
    for (int i=1;i<=m;i++)
    {
        scanf("%s",type);
        if (type[0]==‘C‘) work1();
        else work2();
    }
    return 0;
}
时间: 2024-12-15 10:30:28

BZOJ 2243 染色的相关文章

BZOJ 2243 染色 | 树链剖分模板题进阶版

BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上还是原树上,把两个区间的信息合并的时候,要注意中间相邻两个颜色是否相同. 这代码好长啊啊啊啊 幸好一次过了不然我估计永远也De不出来 #include <cstdio> #include <cstring> #include <algorithm> using namesp

BZOJ 2243 染色(树链剖分好题)

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 7971  Solved: 2990 [Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依

bzoj 2243 染色(树链剖分)

题外话 首先这是个挺裸的题,由于太久没写剖分导致调了好久,前天调了一下午,一直查不到错 昨晚在看春晚的时候突然灵机一动,发现合并的时候出了问题,开电脑把它A掉了= = 感觉自己也蛮拼的 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1:将节点a到节点b路径上所有点都染成颜色c 2:询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"."222"和"1&q

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

[BZOJ 2243] [SDOI 2011] 染色

题目链接:BZOJ - 2243 题目分析 树链剖分...写了200+行...Debug了整整一天+... 静态读代码读了 5 遍 ,没发现错误,自己做小数据也过了. 提交之后全 WA . ————————————— 杯具的分割线 ————————————————— 然后看了别人代码..然后发现.. 我写线段树区间修改竟然没打标记!!!!直接就修改上了!!!最裸的线段树都不会写了!!! Warning!Warning!Warning! 代码 #include <iostream> #inclu

HYSBZ 2243 染色 (树链剖分)

HYSBZ 2243 染色 题目链接 树链剖分,关键在于线段树的维护,对于每个结点要记录下最左边和最右边的颜色,合并的时候,如果颜色相同那么颜色段要减1 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 100005; int dep[N], fa[N], son[N], sz[N

hysbz 2243 染色(树链剖分)

题目链接:hysbz 2243 染色 题目大意:略. 解题思路:树链剖分+线段树的区间合并,但是区间合并比较简单,节点只要记录左右端点的颜色即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1e5 + 5; int N, M, ne, val[maxn], first[maxn], jump[maxn * 2]; int

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

2243: [SDOI2011]染色 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之间有一条无向边.