【BZOJ2243】【SDOI2011】染色(树链剖分+线段树)

来源:互联网 发布:xampp mac使用教程 编辑:程序博客网 时间:2024/05/19 03:20

题目描述

传送门

题解

树链剖分一样就能看出来,更重要的是线段树的处理。
p数组与sum同步,.l/.r分别表示这个区间左端点和右端点的颜色。然后各种乱搞。
查询的时候,在链与链之间,如果颜色一样的话,则需要使当前答案-1。
一节微机课没搞出来,回去之后数学课想了一想,晚上终于调出来了。提交的时候行数200+,删去注释之后只有170+了。。。

代码

#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int max_n=1e5+5;const int max_e=max_n*2;const int max_N=max_n*4;int n,m,x,y,N,u,t,ans;int color[max_n],size[max_n],h[max_n],father[max_n],son[max_n];int top[max_n],num[max_n],tree[max_n];int point[max_n],next[max_e],v[max_e],tot;int sum[max_N],delta[max_N],interval[max_n];struct hp{    int l,r;}p[max_N];inline void add(int x,int y){    ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y;    ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x;}inline void dfs_1(int x,int fa,int dep){    size[x]=1; h[x]=dep; father[x]=fa;    int maxson=0;    for (int i=point[x];i;i=next[i])      if (v[i]!=fa){        dfs_1(v[i],x,dep+1);        size[x]+=size[v[i]];        if (size[v[i]]>maxson){            maxson=size[v[i]];            son[x]=v[i];        }      }}inline void dfs_2(int x,int fa){    if (son[fa]!=x) top[x]=x;    else top[x]=top[fa];    num[x]=++N;    if (son[x]) dfs_2(son[x],x);    for (int i=point[x];i;i=next[i])      if (v[i]!=fa&&v[i]!=son[x])        dfs_2(v[i],x);}inline void update(int now){    if (p[now<<1].r==p[now<<1|1].l)      sum[now]=sum[now<<1]+sum[now<<1|1]-1;    else sum[now]=sum[now<<1]+sum[now<<1|1];    p[now].l=p[now<<1].l;    p[now].r=p[now<<1|1].r;}inline void pushdown(int now,int l,int r,int mid){    if (delta[now]){        sum[now<<1]=1;        delta[now<<1]=delta[now];        p[now<<1].l=p[now<<1].r=delta[now];        sum[now<<1|1]=1;        delta[now<<1|1]=delta[now];        p[now<<1|1].l=p[now<<1|1].r=delta[now];        delta[now]=0;    }}inline void build(int now,int l,int r){    int mid=(l+r)>>1;    if (l==r){        interval[l]=now;        sum[now]=1;        p[now].l=p[now].r=color[tree[l]];        return;    }    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);    update(now);}inline void interval_change(int now,int l,int r,int lrange,int rrange,int v){    int mid=(l+r)>>1;    if (lrange<=l&&r<=rrange){        sum[now]=1;        p[now].l=p[now].r=v;        delta[now]=v;        return;    }    pushdown(now,l,r,mid);    if (lrange<=mid)      interval_change(now<<1,l,mid,lrange,rrange,v);    if (mid+1<=rrange)      interval_change(now<<1|1,mid+1,r,lrange,rrange,v);    update(now);}inline int query(int now,int l,int r,int lrange,int rrange){    int mid=(l+r)>>1,ans=0;    if (lrange<=l&&r<=rrange) return sum[now];    pushdown(now,l,r,mid);    bool pd1=false,pd2=false;    if (lrange<=mid)      ans+=query(now<<1,l,mid,lrange,rrange),pd1=true;    if (mid+1<=rrange)      ans+=query(now<<1|1,mid+1,r,lrange,rrange),pd2=true;    if (pd1&&pd2&&p[now<<1].r==p[now<<1|1].l)      ans--;    return ans;}inline void CHANGE(int u,int t,int x){    int f1=top[u],f2=top[t];    while (f1!=f2){        if (h[f1]<h[f2]){            swap(u,t);            swap(f1,f2);        }        interval_change(1,1,N,num[f1],num[u],x);        u=father[f1];        f1=top[u];    }    if (num[u]>num[t]) swap(u,t);    interval_change(1,1,N,num[u],num[t],x);}inline int QUERY(int u,int t){    int f1=top[u],f2=top[t],ans=0;    while (f1!=f2){        if (h[f1]<h[f2]){            swap(u,t);            swap(f1,f2);        }        ans+=query(1,1,N,num[f1],num[u]);        //pushdown        int k=query(1,1,N,num[f1],num[f1]);        k=query(1,1,N,num[father[f1]],num[father[f1]]);        if (p[interval[num[f1]]].l==p[interval[num[father[f1]]]].l)           ans--;        u=father[f1];        f1=top[u];    }    if (num[u]>num[t]) swap(u,t);    ans+=query(1,1,N,num[u],num[t]);    return ans;}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;++i)      scanf("%d",&color[i]);    for (int i=1;i<n;++i){        scanf("%d%d",&x,&y);        add(x,y);    }    dfs_1(1,0,1);    dfs_2(1,0);    for (int i=1;i<=n;++i)      tree[num[i]]=i;    build(1,1,N);    for (int i=1;i<=m;++i){        char ch=getchar();        while (ch!='C'&&ch!='Q') ch=getchar();        if (ch=='C'){            scanf("%d%d%d",&u,&t,&x);            CHANGE(u,t,x);        }        else{            scanf("%d%d",&u,&t);            ans=QUERY(u,t);            printf("%d\n",ans);        }    }}

总结

①关于线段树的任何操作(包括有时候乱搞的直接查询编号),都要思考一下有没有pushdown,即当前也许只是打了标记,没有更新到最新值。
②自己写input不要写错了。

0 0
原创粉丝点击