HYSBZ 2243(染色)

题目链接:传送门

题目大意:中文题,略

题目思路:树链剖分,区间更新,区间查询。

闲谈:      只想说这道题做的好苦逼。。去长春现场赛之前就没A,回来后又做了2天才A掉,蒟蒻太菜了

     这道题也没有想象中那么难,就是代码有点长。。

     在查询的时候注意判断端点交界处如果相同则答案-1。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cctype>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <climits>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define fi first
#define se second
#define ping(x,y) ((x-y)*(x-y))
#define mst(x,y) memset(x,y,sizeof(x))
#define mcp(x,y) memcpy(x,y,sizeof(y))
using namespace std;
#define gamma 0.5772156649015328606065120
#define MOD 1000000007
#define inf 0x3f3f3f3f
#define N 100005
#define maxn 30010
typedef pair<int,int> PII;
typedef long long LL;
LL read(){
    LL x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();}
    return x*f;
}
int n,m,k,sz,L,R;
int a[N],mrk[N<<2];
struct Seg{int l,r,v;}seg[N<<2];
int son[N],siz[N],id[N],tid,posi[N];
int top[N],fa[N],dep[N],head[N],hcnt;
struct Node{int to,nxt;}node[N<<1];
void dfs1(int u,int f,int deep){
    dep[u]=deep,fa[u]=f,siz[u]=1;
    for(int i=head[u];~i;i=node[i].nxt){
        int e=node[i].to;
        if(e==f)continue;
        dfs1(e,u,deep+1);
        siz[u]+=siz[e];
        if(!son[u]||siz[son[u]]<siz[e])
            son[u]=e;
    }
}
void dfs2(int u,int tp){
    top[u]=tp,id[u]=++tid,posi[tid]=u;
    if(!son[u])return;dfs2(son[u],tp);
    for(int i=head[u];~i;i=node[i].nxt){
        int e=node[i].to;
        if(!id[e])dfs2(e,e);
    }
}
void pushdown(int rt){
    seg[rt<<1].v=seg[rt<<1|1].v=1;
    seg[rt<<1].l=seg[rt<<1].r=mrk[rt];
    seg[rt<<1|1].l=seg[rt<<1|1].r=mrk[rt];
    mrk[rt<<1]=mrk[rt<<1|1]=mrk[rt];mrk[rt]=-1;
}
int query(int rt,int l,int r){
    if(L<=l&&r<=R)return seg[rt].v;
    int mid=l+r>>1,temp=0,t1=-1,t2=-1;
    if(~mrk[rt])pushdown(rt);
    if(L<=mid)t1=seg[rt<<1].r,temp+=query(lson);
    if(R>mid) t2=seg[rt<<1|1].l,temp+=query(rson);
    seg[rt].l=seg[rt<<1].l,seg[rt].r=seg[rt<<1|1].r;
    seg[rt].v=seg[rt<<1].v+seg[rt<<1|1].v-(seg[rt<<1].r==seg[rt<<1|1].l);
    temp-=(t1==t2&&t1!=-1);
    return temp;
}
void update(int rt,int l,int r,int v){
    if(L<=l&&r<=R){seg[rt].v=1,seg[rt].l=seg[rt].r=mrk[rt]=v;return;}
    int mid=l+r>>1;
    if(~mrk[rt])pushdown(rt);
    if(L<=mid)update(lson,v);
    if(R>mid) update(rson,v);
    seg[rt].l=seg[rt<<1].l,seg[rt].r=seg[rt<<1|1].r;
    seg[rt].v=seg[rt<<1].v+seg[rt<<1|1].v-(seg[rt<<1].r==seg[rt<<1|1].l);
}
int findp(int rt,int l,int r,int L){
    if(l==r)return seg[rt].l;
    int mid=l+r>>1,temp;
    if(~mrk[rt])pushdown(rt);
    if(L<=mid)return findp(lson,L);
    else return findp(rson,L);
}
void lca(int x,int y){
    int res=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        L=id[top[x]],R=id[x];
        res+=query(1,1,n);
        L=id[x];
        if(findp(1,1,n,id[top[x]])==findp(1,1,n,id[fa[top[x]]]))--res; ///看两端是否相同
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    L=id[x],R=id[y];
    res+=query(1,1,n);
    printf("%d\n",res);
}
void change(int x,int y,int v){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        L=id[top[x]],R=id[x];
        update(1,1,n,v);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    L=id[x],R=id[y];
    update(1,1,n,v);
}
void build(int rt,int l,int r){
    if(l==r){seg[rt].l=seg[rt].r=a[posi[l]],seg[rt].v=1;return;}
    int mid=l+r>>1;
    build(lson);build(rson);
    seg[rt].v=seg[rt<<1].v+seg[rt<<1|1].v-(seg[rt<<1].r==seg[rt<<1|1].l);
    seg[rt].l=seg[rt<<1].l,seg[rt].r=seg[rt<<1|1].r;
}
int main(){
    int i,j,group,x,y,v;
    n=read(),m=read();mst(head,-1);mst(mrk,-1);
    for(i=1;i<=n;++i)a[i]=read();
    for(i=1;i<n;++i){
        x=read(),y=read();
        node[hcnt].to=y;node[hcnt].nxt=head[x],head[x]=hcnt++;
        node[hcnt].to=x,node[hcnt].nxt=head[y],head[y]=hcnt++;
    }
    dfs1(1,1,1);dfs2(1,1);build(1,1,n);
    char ch;
    while(m--){
        scanf(" %c",&ch);
        x=read(),y=read();
        if(ch==‘Q‘) lca(x,y);
        else v=read(),change(x,y,v);
    }
    return 0;
}
时间: 2024-10-29 19:12:21

HYSBZ 2243(染色)的相关文章

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

(树链剖分+区间合并)HYSBZ - 2243 染色

题意: 两个操作: 1.把一条树链上的所有点权值变为w. 2.查询一条树链上有多少个颜色段 分析: 一看就是区间合并,做这到题首先需要一定的区间合并基础, 不过这题合并这部分在线段树区间合并中已经算是非常的简单的了. 线段树部分没有难度. 那么难点在于,在往LCA上走的时候,我们如何进行区间合并. 本来我想着, 在向上走的时候顺便进行区间判断并且合并,但是似乎有问题. 其实,可以将两步分开,先算出区间没合并之前的颜色段数,再次进行Top,判断颜色是否相等,相等就减掉. 代码: 1 #includ

HYSBZ 2243 染色 (线段树+树链剖分)

题意:中文题. 析:真是一个好题,但是我TLE了两天,就是因为输入那个询问数,我当作边数了,结果就是一个TLE... 大体思路,就是先进行用树链剖分,然后用线段树来维护,维护每个区间的不同数的个数,和每个数的值,在求的时候,在两个端点进行判断,是不是同一种,如果是就减去1,不是则不变. 而且发现一个问题,就是网上的代码所以输出的和我的不一样,但是都AC了,不知道是不是数据水.也不知道谁的对. 代码如下: #pragma comment(linker, "/STACK:1024000000,102

HYSBZ 2243 染色 (树链拆分)

主题链接~~> 做题情绪:这题思路好想.调试代码调试了好久.第一次写线段树区间合并. 解题思路: 树链剖分 + 线段树区间合并 线段树的端点记录左右区间的颜色.颜色数目.合并的时候就用区间合并的思想. 还要注意一点.在由一条链转到还有一条链的时候要推断当前节点是否与父亲节点是否同一种颜色. 代码: #include<iostream> #include<sstream> #include<map> #include<cmath> #include<

HYSBZ 2243 染色 树链剖分 线段树

这题对最简单的树链剖分做了一些变化,在链的转移过程中要考虑前后链相邻节点颜色是否相同. 对于线段树,只要维护三个值,左端点颜色,右端点颜色还有区间颜色总数就好了. #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #include <bitset> #include <queue> #include

HYSBZ 2243 树链剖分(区间更新,区间查询)较难

http://www.lydsy.com/JudgeOnline/problem.php?id=2243 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"."222"和"1". 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数

HYSBZ 2243

//Accepted 18440 KB 5556 ms /* source:HYSBZ 2243 time :2015.5.29 by :songt */ /*题解: 树链剖分 */ #include <cstdio> #include <cstring> const int imax_n = 100005; struct Edge { int u,v; Edge(){} Edge(int u,int v):u(u),v(v){} }edge[2*imax_n]; int head

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

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