zoukankan      html  css  js  c++  java
  • P2486 [SDOI2011]染色

    题目链接:https://www.luogu.com.cn/problem/P2486

    题是好题,毒也很毒。

    一杯酒,一键盘,一份代码敲一天,缝缝补补又几年;

    最后喜得中国红;

     本题质量还是非常上乘的。

    一,仔细理解题意;

    注意到他是求一段区间内有多少个颜色段,并不是求一段区间内有多少种颜色。一开始因为这个十分疑惑该怎么用线段树进行维护。

    二,如何维护区间内多少段颜色段。

    考虑到线段树,对于区间更改颜色,这个很简单了。那我们如何把两个子区间合并成一个大区间呢?

    假设一段连续的区间值为:123345,首先定义sum[l-r]表示区间[l,r]有多少个颜色段;那么

    sum[1-6]=sum[1-3] + sum[4-6];然后注意到有可能3跟4是一种颜色,我们可以通过在维护每个区间的左右端点颜色,进行判断。

    如果3-4是一种颜色,那么sum[1-6]就要减1.

    所以代码为:

    sum[id] = sum[id * 2] + sum[id * 2 + 1];
    if(R_color[id * 2] == L_color[id * 2 + 1]) sum[id] --;

     我们通过树链剖分可以轻松的对每个区间进行维护,树链剖分就不细讲了。

    我们继续考虑一种情况。

     上为样例的一个微改图;

    如果我们此时查询编号为5和3结点之间有多少个不同的颜色段。

    首先他的重链是1-2-4这条链,用紫色表明了。

    所以在查询的时候,我会先查询4-4(注意查询区间是dfs序,不是编号)这个区间,发现1个颜色段。

    在去查询6-6这个区间,发现1个颜色段。

    最后查询(1-2)这个区间发现一个颜色段。

    我们把他加起来为3个颜色段,但是根据图而言是只有一个颜色段的。

    产生差异的主要原因,在于他当前结点fx区间[l-r]有可能会跟结点fx的父亲区间相同颜色,从而产生差异。

    所以,我们在写的时候,需要把他这条链上最顶上(也就是区间的l值位置)的颜色用ans1记录下来并与他父亲的那个区间的右端点进行比较。如果相同,则要减一。

    同样,因为另外一个结点做相同考虑,用ans2记录下来。

    最后还有一种情况,需要考虑仔细:

     如果我们考虑结点编号为4,10之间的颜色段,一定要注意ans1和ans2的维护。

    因为这个维护错了不知道多少次。

    #include"stdio.h"
    #include"string.h"
    #include"algorithm"
    using namespace std;
    
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    const int N = 200010;
    
    int n,q,root,mod,m;
    int head[N],ver[N],Next[N],tot;///树的结构存储
    int val[N];///存储每个结点的信息
    int d[N],son[N],far[N],Size[N];///结点的深度,重儿子,祖先
    int a[N],sum[N * 4];///线段树上的结点值,maxx,sum值
    int L_color[N * 4],R_color[N * 4];///一个区间最左最右边的颜色
    int dfn[N],top[N],id[N];///存储dfs序,top是条链的祖先,id是每个结点在dfn中序列的下标位置
    int cnt;///表示的是dfs序列的最后一个位置
    int laze[N * 4],now[N * 4];
    
    void add(int x,int y){ ///添加树边
        ver[++ tot] = y;  Next[tot] = head[x]; head[x] = tot;
    }
    
    void Build_Tree(int id,int l,int r)
    {
        laze[id] = now[id] = 0;
        L_color[id] = R_color[id] = 0;
        if(l == r)
        {
            laze[id] = 0; now[id] = 0;
            L_color[id] = R_color[id] = val[dfn[l]];
            sum[id] = 1; return ;
        }
        int mid = (l + r) >> 1;
        Build_Tree(id * 2,l,mid);
        Build_Tree(id * 2 + 1,mid + 1,r);
    
        sum[id] = sum[id * 2] + sum[id * 2 + 1];
        L_color[id] = L_color[id * 2]; R_color[id] = R_color[id * 2 + 1];
        if(R_color[id * 2] == L_color[id * 2 + 1]) sum[id] --;
        return ;
    }
    
    void spread(int id,int l,int r)
    {
        int mid = (l + r) >> 1;
        if(laze[id])
        {
            sum[id * 2] = 1;
            sum[id * 2 + 1] = 1;
            laze[id * 2] = 1; now[id * 2] = now[id];
            laze[id * 2 + 1] = 1; now[id * 2 + 1] = now[id];
            L_color[id * 2] = R_color[id * 2] = now[id];
            L_color[id * 2 + 1] = R_color[id * 2 + 1] = now[id];
            laze[id] = 0; now[id] = 0;
        }
        return ;
    }
    
    void Update(int id,int L,int R,int l,int r,int x)///将loc上的值进行更新
    {
        if(l <= L && r >= R)
        {
            laze[id] = 1; now[id] = x;
            sum[id] = 1; L_color[id] = R_color[id] = x;
            return ;
        }
        spread(id,L,R);
        int mid = (L + R) >> 1;
        if(l <= mid) Update(id * 2,L,mid,l,r,x);
        if(r > mid) Update(id * 2 + 1,mid + 1,R,l,r,x);
        sum[id] = sum[id * 2] + sum[id * 2 + 1];
        if(R_color[id * 2] == L_color[id * 2 + 1]) sum[id] --;
        L_color[id] = L_color[id * 2]; R_color[id] = R_color[id * 2 + 1];
        return ;
    }
    
    int now_L = 0,now_R = 0;
    int Query_sum(int id,int L,int R,int l,int r)///查询[l,r]区间和
    {
        if(L > r || R < l) return 0;
        if(l <= L && r >= R)
            {
               if(l == L)
               now_L = L_color[id];
               if(r == R)
               now_R = R_color[id];
               return sum[id];
            }
        spread(id,L,R);
        int mid = (L + R) >> 1;
        int ans = Query_sum(id * 2,L,mid,l,r)+ Query_sum(id * 2 + 1,mid + 1,R,l,r);
        if(l <= mid && r > mid)
        {
            if(R_color[id * 2] == L_color[id * 2 + 1])
                ans --;
        }
        sum[id] = sum[id * 2] + sum[id * 2 + 1];
        if(R_color[id * 2] == L_color[id * 2 + 1]) sum[id] --;
        L_color[id] = L_color[id * 2]; R_color[id] = R_color[id * 2 + 1];
        return ans;
    }
    
    void dfs1(int u,int f,int dep)///dfs1指在处理d数组,son数组,far数组,Size数组
    {
        d[u] = dep; far[u] = f;
        Size[u] = 1; son[u] = -1;
        for(int i = head[u]; i; i = Next[i]){
            int v = ver[i];
            if(v == f) continue;
            dfs1(v,u,dep+1);
            Size[u] += Size[v];
            if(son[u] == -1 || Size[son[u]] < Size[v])
               son[u] = v;
        }
    }
    
    void dfs2(int u,int T)///旨在处理重链,和dfs序列
    {
        dfn[++ cnt] = u;id[u] = cnt;
        top[u] = T;
        if(son[u] == -1) return ;
        dfs2(son[u],T);
        for(int i = head[u]; i; i = Next[i]){
            int v = ver[i];
            if(v != son[u] && v != far[u]){
                dfs2(v,v);
            }
        }
    }
    
    int main()
    {
        n = read(); m = read();
        for(int i = 1; i <= n; i ++)
            val[i] = read();
        for(int i = 1; i < n; i ++)
        {
            int x,y; scanf("%d%d",&x,&y);
            add(x,y); add(y,x);
        }
        q = m;
        cnt = 0; root = 1;
        dfs1(root,root,1);
        dfs2(root,root);
        Build_Tree(1,1,n);
        while(q --)
        {
           int op;char str[15]; scanf("%s",str);
           if(str[0] == 'C') op = 1; else op = 0;
           if(op == 1)
           {
               int x,y,c; scanf("%d%d%d",&x,&y,&c);
               int fx = top[x]; int fy = top[y];
               while(fx != fy)
               {
                 if(d[fx] > d[fy])
                    {
                        Update(1,1,n,id[fx],id[x],c);
                        x = far[fx]; fx = top[x];
                    }
                else {
                     Update(1,1,n,id[fy],id[y],c);
                     y = far[fy]; fy = top[y];
                    }
               }
               if(id[x] <= id[y])
                 Update(1,1,n,id[x],id[y],c);
               else Update(1,1,n,id[y],id[x],c);
    
           } else {
               now_L = 0,now_R = 0;
               int ans1 = 0,ans2 = 0;
               int x,y; scanf("%d%d",&x,&y);
               int fx = top[x],fy = top[y];
               int ans = 0;int ttt = 0;
               while(fx != fy)
               {
                    if(d[fx] > d[fy])
                    {
                         ttt = Query_sum(1,1,n,id[fx],id[x]);
                         ans += ttt;
                         x = far[fx]; fx = top[x];
                         if(now_R == ans1) ans --;
                         ans1 = now_L;
                    } else
                    {
                        ttt = Query_sum(1,1,n,id[fy],id[y]);
                        ans += ttt;
                        y = far[fy]; fy = top[y];
                        if(now_R == ans2) ans --;
                        ans2 = now_L;
                    }
               }
               if(d[x] < d[y])
                  {
                      ttt = Query_sum(1,1,n,id[x],id[y]);  ans += ttt;
                      if(now_L == ans1) ans --; if(now_R == ans2) ans --;
                  }
               else {
                    ttt = Query_sum(1,1,n,id[y],id[x]);  ans += ttt;
                    if(now_R == ans1) ans --; if(now_L == ans2) ans --;
               }
    
    
               printf("%d
    ",ans);
           }
        }
    }
    
  • 相关阅读:
    查看每个核的资源情况
    什么时候使用NO_UNNEST
    走FILTER效率高的2种情况
    PL/SQL 包头和包体
    产品研发要配合好
    ElasticSearch 文档并发处理以及文档路由
    ES(ElasticSearch) 索引创建
    BaikalDB技术实现内幕(三)--代价模型实现
    腾讯位置服务地图SDK自定义地图和路况
    mysql数据库优化
  • 原文地址:https://www.cnblogs.com/yrz001030/p/12359801.html
Copyright © 2011-2022 走看看